private void Compact <T>(T functions, long untilAddress, VariableLengthStructSettings <Key, Value> variableLengthStructSettings) where T : IFunctions <Key, Value, Input, Output, Context> { var fhtSession = fht.NewSession(); var originalUntilAddress = untilAddress; var tempKv = new FasterKV <Key, Value, Input, Output, Context, T> (fht.IndexSize, functions, new LogSettings(), comparer: fht.Comparer, variableLengthStructSettings: variableLengthStructSettings); var tempKvSession = tempKv.NewSession(); using (var iter1 = fht.Log.Scan(fht.Log.BeginAddress, untilAddress)) { while (iter1.GetNext(out RecordInfo recordInfo)) { ref var key = ref iter1.GetKey(); ref var value = ref iter1.GetValue(); if (recordInfo.Tombstone) { tempKvSession.Delete(ref key, default, 0);
/// <inheritdoc /> public 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 FasterSession : IFasterSession { switch (current.phase) { case Phase.PREPARE_GROW: case Phase.IN_PROGRESS_GROW: case Phase.REST: return; default: throw new FasterException("Invalid Enum Argument"); } }
protected void CollectMetadata <Key, Value>(SystemState next, FasterKV <Key, Value> faster) { // Collect object log offsets only after flushes // are completed var seg = faster.hlog.GetSegmentOffsets(); if (seg != null) { faster._hybridLogCheckpoint.info.objectLogSegmentOffsets = new long[seg.Length]; Array.Copy(seg, faster._hybridLogCheckpoint.info.objectLogSegmentOffsets, seg.Length); } // Temporarily block new sessions from starting, which may add an entry to the table and resize the // dictionary. There should be minimal contention here. lock (faster._activeSessions) // write dormant sessions to checkpoint foreach (var kvp in faster._activeSessions) { kvp.Value.AtomicSwitch(next.version - 1); } }
internal ClientSession( FasterKV <Key, Value> fht, FasterKV <Key, Value> .FasterExecutionContext <Input, Output, Context> ctx, Functions functions, bool supportAsync) { this.fht = fht; this.ctx = ctx; this.functions = functions; SupportAsync = supportAsync; LatestCommitPoint = new CommitPoint { UntilSerialNo = -1, ExcludedSerialNos = null }; FasterSession = new AsyncFasterSession(this); // Session runs on a single thread if (!supportAsync) { UnsafeResumeThread(); } }
/// <inheritdoc /> public void GlobalAfterEnteringState <Key, Value>( SystemState next, FasterKV <Key, Value> faster) where Key : new() where Value : new() { switch (next.phase) { case Phase.PREPARE_GROW: faster.epoch.BumpCurrentEpoch(() => faster.GlobalStateMachineStep(next)); break; case Phase.IN_PROGRESS_GROW: case Phase.REST: // nothing to do break; default: throw new FasterException("Invalid Enum Argument"); } }
/// <summary> /// Compact the log until specified address, moving active records to the tail of the log. /// </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="untilAddress">Compact log until this address</param> /// <param name="shiftBeginAddress">Whether to shift begin address to untilAddress after compaction. To avoid /// data loss on failure, set this to false, and shift begin address only after taking a checkpoint. This /// ensures that records written to the tail during compaction are first made stable.</param> /// <returns>Address until which compaction was done</returns> public long Compact <Input, Output, Context, Functions, CompactionFunctions>(Functions functions, CompactionFunctions cf, long untilAddress, bool shiftBeginAddress) where Functions : IFunctions <Key, Value, Input, Output, Context> where CompactionFunctions : ICompactionFunctions <Key, Value> { if (untilAddress > fht.Log.SafeReadOnlyAddress) { throw new FasterException("Can compact only until Log.SafeReadOnlyAddress"); } var originalUntilAddress = untilAddress; var lf = new LogCompactionFunctions <Key, Value, Input, Output, Context, Functions>(functions); using var fhtSession = fht.For(lf).NewSession <LogCompactionFunctions <Key, Value, Input, Output, Context, Functions> >(); VariableLengthStructSettings <Key, Value> variableLengthStructSettings = null; if (allocator is VariableLengthBlittableAllocator <Key, Value> varLen) { variableLengthStructSettings = new VariableLengthStructSettings <Key, Value> { keyLength = varLen.KeyLength, valueLength = varLen.ValueLength, }; } using (var tempKv = new FasterKV <Key, Value>(fht.IndexSize, new LogSettings { LogDevice = new NullDevice(), ObjectLogDevice = new NullDevice() }, comparer: fht.Comparer, variableLengthStructSettings: variableLengthStructSettings)) using (var tempKvSession = tempKv.NewSession <Input, Output, Context, Functions>(functions)) { using (var iter1 = fht.Log.Scan(fht.Log.BeginAddress, untilAddress)) { while (iter1.GetNext(out var recordInfo)) { ref var key = ref iter1.GetKey(); ref var value = ref iter1.GetValue(); if (recordInfo.Tombstone || cf.IsDeleted(key, value)) { tempKvSession.Delete(ref key, default, 0);
private void LogScanForValidity(ref long untilAddress, ref long scanUntil, ref FasterKV <Key, Value, Input, Output, Context, LogCompactFunctions> tempKv) { while (scanUntil < fht.Log.SafeReadOnlyAddress) { untilAddress = scanUntil; scanUntil = fht.Log.SafeReadOnlyAddress; int cnt = 0; using (var iter2 = fht.Log.Scan(untilAddress, scanUntil)) { while (iter2.GetNext(out RecordInfo recordInfo, out Key key, out Value value)) { tempKv.Delete(ref key, default(Context), 0); if (++cnt % 1000 == 0) { fht.Refresh(); } } } fht.Refresh(); } }
public FasterKVIterator(FasterKV <Key, Value> fht, Functions functions, long untilAddress) { this.fht = fht; enumerationPhase = 0; VariableLengthStructSettings <Key, Value> variableLengthStructSettings = null; if (fht.hlog is VariableLengthBlittableAllocator <Key, Value> varLen) { variableLengthStructSettings = new VariableLengthStructSettings <Key, Value> { keyLength = varLen.KeyLength, valueLength = varLen.ValueLength, }; } tempKv = new FasterKV <Key, Value>(fht.IndexSize, new LogSettings { LogDevice = new NullDevice(), ObjectLogDevice = new NullDevice(), MutableFraction = 1 }, comparer: fht.Comparer, variableLengthStructSettings: variableLengthStructSettings); tempKvSession = tempKv.NewSession <Input, Output, Context, Functions>(functions); iter1 = fht.Log.Scan(fht.Log.BeginAddress, untilAddress); }
internal ClientSession( FasterKV <Key, Value> fht, FasterKV <Key, Value> .FasterExecutionContext <Input, Output, Context> ctx, Functions functions, bool supportAsync, IVariableLengthStruct <Value, Input> variableLengthStruct) { this.fht = fht; this.ctx = ctx; this.functions = functions; SupportAsync = supportAsync; LatestCommitPoint = new CommitPoint { UntilSerialNo = -1, ExcludedSerialNos = null }; FasterSession = new AsyncFasterSession(this); this.variableLengthStruct = variableLengthStruct; 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"); } } // Session runs on a single thread if (!supportAsync) { UnsafeResumeThread(); } }
/// <inheritdoc /> public virtual void GlobalBeforeEnteringState <Key, Value>(SystemState next, FasterKV <Key, Value> faster) { switch (next.Phase) { case Phase.PREPARE: lastVersion = faster.systemState.Version; if (faster._hybridLogCheckpoint.IsDefault()) { faster._hybridLogCheckpointToken = Guid.NewGuid(); faster.InitializeHybridLogCheckpoint(faster._hybridLogCheckpointToken, next.Version); } faster._hybridLogCheckpoint.info.version = next.Version; faster.ObtainCurrentTailAddress(ref faster._hybridLogCheckpoint.info.startLogicalAddress); break; case Phase.WAIT_FLUSH: faster._hybridLogCheckpoint.info.headAddress = faster.hlog.HeadAddress; faster._hybridLogCheckpoint.info.beginAddress = faster.hlog.BeginAddress; faster._hybridLogCheckpoint.info.nextVersion = next.Version; break; case Phase.PERSISTENCE_CALLBACK: CollectMetadata(next, faster); faster.WriteHybridLogMetaInfo(); faster.lastVersion = lastVersion; break; case Phase.REST: faster._hybridLogCheckpoint.Dispose(); var nextTcs = new TaskCompletionSource <LinkedCheckpointInfo>(TaskCreationOptions.RunContinuationsAsynchronously); faster.checkpointTcs.SetResult(new LinkedCheckpointInfo { NextTask = nextTcs.Task }); faster.checkpointTcs = nextTcs; break; } }
/// <inheritdoc /> public void GlobalBeforeEnteringState <Key, Value, Input, Output, Context, Functions>( SystemState next, FasterKV <Key, Value, Input, Output, Context, Functions> faster) where Key : new() where Value : new() where Functions : IFunctions <Key, Value, Input, Output, Context> { switch (next.phase) { case Phase.PREP_INDEX_CHECKPOINT: Debug.Assert(faster._indexCheckpointToken == default && faster._hybridLogCheckpointToken == default); var fullCheckpointToken = Guid.NewGuid(); faster._indexCheckpointToken = fullCheckpointToken; faster._hybridLogCheckpointToken = fullCheckpointToken; faster.InitializeIndexCheckpoint(faster._indexCheckpointToken); faster.InitializeHybridLogCheckpoint(faster._hybridLogCheckpointToken, next.version); break; case Phase.PREPARE: if (faster.UseReadCache && faster.ReadCache.BeginAddress != faster.ReadCache.TailAddress) { throw new FasterException("Index checkpoint with read cache is not supported"); } faster.TakeIndexFuzzyCheckpoint(); break; case Phase.WAIT_FLUSH: faster._indexCheckpoint.info.num_buckets = faster.overflowBucketsAllocator.GetMaxValidAddress(); faster.ObtainCurrentTailAddress(ref faster._indexCheckpoint.info.finalLogicalAddress); break; case Phase.PERSISTENCE_CALLBACK: faster.WriteIndexMetaInfo(); faster._indexCheckpointToken = default; break; } }
/// <inheritdoc /> public void GlobalBeforeEnteringState <Key, Value>( SystemState next, FasterKV <Key, Value> faster) { switch (next.phase) { case Phase.PREP_INDEX_CHECKPOINT: if (faster._indexCheckpoint.IsDefault()) { faster._indexCheckpointToken = Guid.NewGuid(); faster.InitializeIndexCheckpoint(faster._indexCheckpointToken); } faster.ObtainCurrentTailAddress(ref faster._indexCheckpoint.info.startLogicalAddress); faster.TakeIndexFuzzyCheckpoint(); break; case Phase.WAIT_INDEX_CHECKPOINT: case Phase.WAIT_INDEX_ONLY_CHECKPOINT: break; case Phase.REST: // If the tail address has already been obtained, because another task on the state machine // has done so earlier (e.g. FullCheckpoint captures log tail at WAIT_FLUSH), don't update // the tail address. if (faster.ObtainCurrentTailAddress(ref faster._indexCheckpoint.info.finalLogicalAddress)) { faster._indexCheckpoint.info.num_buckets = faster.overflowBucketsAllocator.GetMaxValidAddress(); } if (!faster._indexCheckpoint.IsDefault()) { faster.WriteIndexMetaInfo(); faster._indexCheckpoint.Reset(); } break; } }
/// <inheritdoc /> public ValueTask OnThreadState <Key, Value, Input, Output, Context, Functions>( SystemState current, SystemState prev, FasterKV <Key, Value, Input, Output, Context, Functions> faster, FasterKV <Key, Value, Input, Output, Context, Functions> .FasterExecutionContext ctx, ClientSession <Key, Value, Input, Output, Context, Functions> clientSession, bool async = true, CancellationToken token = default) where Key : new() where Value : new() where Functions : IFunctions <Key, Value, Input, Output, Context> { switch (current.phase) { case Phase.PREPARE_GROW: case Phase.IN_PROGRESS_GROW: case Phase.REST: return(default); default: throw new FasterException("Invalid Enum Argument"); } }
/// <inheritdoc /> public void GlobalBeforeEnteringState <Key, Value, Input, Output, Context, Functions>( SystemState next, FasterKV <Key, Value, Input, Output, Context, Functions> faster) where Key : new() where Value : new() where Functions : IFunctions <Key, Value, Input, Output, Context> { switch (next.phase) { case Phase.PREPARE_GROW: // nothing to do break; case Phase.IN_PROGRESS_GROW: // Set up the transition to new version of HT var numChunks = (int)(faster.state[faster.resizeInfo.version].size / Constants.kSizeofChunk); if (numChunks == 0) { numChunks = 1; // at least one chunk } faster.numPendingChunksToBeSplit = numChunks; faster.splitStatus = new long[numChunks]; faster.Initialize(1 - faster.resizeInfo.version, faster.state[faster.resizeInfo.version].size * 2, faster.sectorSize); faster.resizeInfo.version = 1 - faster.resizeInfo.version; break; case Phase.REST: // nothing to do break; default: throw new FasterException("Invalid Enum Argument"); } }
private static async ValueTask <ReadAsyncResult <Input, Output, Context, Functions> > SlowReadAsync <Input, Output, Context, Functions>( FasterKV <Key, Value> @this, ClientSession <Key, Value, Input, Output, Context, Functions> clientSession, PendingContext <Input, Output, Context> pendingContext, CancellationToken token = default) where Functions : IFunctions <Key, Value, Input, Output, Context> { var diskRequest = @this.ScheduleGetFromDisk(clientSession.ctx, ref pendingContext); clientSession.ctx.ioPendingRequests.Add(pendingContext.id, pendingContext); clientSession.ctx.asyncPendingCount++; clientSession.ctx.pendingReads.Add(); try { token.ThrowIfCancellationRequested(); if (@this.epoch.ThisInstanceProtected()) { throw new NotSupportedException("Async operations not supported over protected epoch"); } diskRequest = await diskRequest.asyncOperation.Task; } catch { clientSession.ctx.ioPendingRequests.Remove(pendingContext.id); clientSession.ctx.asyncPendingCount--; throw; } finally { clientSession.ctx.pendingReads.Remove(); } return(new ReadAsyncResult <Input, Output, Context, Functions>(@this, clientSession, pendingContext, diskRequest)); }
public LegacyFasterSession(FasterKV <Key, Value, Input, Output, Context, Functions> fasterKV) { _fasterKV = fasterKV; }
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(); } }
/// <inheritdoc /> public 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 FasterSession : IFasterSession { switch (current.phase) { case Phase.PREPARE: if (ctx != null) { if (!ctx.markers[EpochPhaseIdx.Prepare]) { if (!faster.RelaxedCPR) { faster.AcquireSharedLatchesForAllPendingRequests(ctx); } ctx.markers[EpochPhaseIdx.Prepare] = true; } faster.epoch.Mark(EpochPhaseIdx.Prepare, current.version); } if (faster.epoch.CheckIsComplete(EpochPhaseIdx.Prepare, current.version)) { faster.GlobalStateMachineStep(current); } break; case Phase.IN_PROGRESS: if (ctx != null) { // Need to be very careful here as threadCtx is changing var _ctx = prev.phase == Phase.IN_PROGRESS ? ctx.prevCtx : ctx; var tokens = faster._hybridLogCheckpoint.info.checkpointTokens; if (!faster.SameCycle(current) || tokens == null) { return; } if (!_ctx.markers[EpochPhaseIdx.InProgress]) { faster.AtomicSwitch(ctx, ctx.prevCtx, _ctx.version, tokens); faster.InitContext(ctx, ctx.prevCtx.guid, ctx.prevCtx.serialNum); // Has to be prevCtx, not ctx ctx.prevCtx.markers[EpochPhaseIdx.InProgress] = true; } faster.epoch.Mark(EpochPhaseIdx.InProgress, current.version); } // Has to be prevCtx, not ctx if (faster.epoch.CheckIsComplete(EpochPhaseIdx.InProgress, current.version)) { faster.GlobalStateMachineStep(current); } break; case Phase.WAIT_PENDING: if (ctx != null) { if (!faster.RelaxedCPR && !ctx.prevCtx.markers[EpochPhaseIdx.WaitPending]) { if (ctx.prevCtx.HasNoPendingRequests) { ctx.prevCtx.markers[EpochPhaseIdx.WaitPending] = true; } else { break; } } faster.epoch.Mark(EpochPhaseIdx.WaitPending, current.version); } if (faster.epoch.CheckIsComplete(EpochPhaseIdx.WaitPending, current.version)) { faster.GlobalStateMachineStep(current); } break; case Phase.REST: break; } }
/// <inheritdoc /> public void GlobalAfterEnteringState <Key, Value>( SystemState start, FasterKV <Key, Value> faster) { }
/// <inheritdoc /> public void GlobalBeforeEnteringState <Key, Value>( SystemState next, FasterKV <Key, Value> faster) { }
/// <summary> /// Compact the log until specified address, moving active /// records to the tail of the log /// </summary> /// <param name="untilAddress"></param> public void Compact(long untilAddress) { long originalUntilAddress = untilAddress; var tempKv = new FasterKV <Key, Value, Input, Output, Context, LogCompactFunctions> (fht.IndexSize, new LogCompactFunctions(), new LogSettings(), comparer: fht.Comparer); tempKv.StartSession(); int cnt = 0; using (var iter1 = fht.Log.Scan(fht.Log.BeginAddress, untilAddress)) { while (iter1.GetNext(out RecordInfo recordInfo, out Key key, out Value value)) { if (recordInfo.Tombstone) { tempKv.Delete(ref key, default(Context), 0); } else { tempKv.Upsert(ref key, ref value, default(Context), 0); } if (++cnt % 1000 == 0) { fht.Refresh(); tempKv.Refresh(); } } } // TODO: Scan until SafeReadOnlyAddress long scanUntil = untilAddress; LogScanForValidity(ref untilAddress, ref scanUntil, ref tempKv); // Make sure key wasn't inserted between SafeReadOnlyAddress and TailAddress cnt = 0; using (var iter3 = tempKv.Log.Scan(tempKv.Log.BeginAddress, tempKv.Log.TailAddress)) { while (iter3.GetNext(out RecordInfo recordInfo, out Key key, out Value value)) { if (!recordInfo.Tombstone) { if (fht.ContainsKeyInMemory(ref key, scanUntil) == Status.NOTFOUND) { fht.Upsert(ref key, ref value, default(Context), 0); } } if (++cnt % 1000 == 0) { fht.Refresh(); tempKv.Refresh(); } if (scanUntil < fht.Log.SafeReadOnlyAddress) { LogScanForValidity(ref untilAddress, ref scanUntil, ref tempKv); } } } tempKv.StopSession(); tempKv.Dispose(); ShiftBeginAddress(originalUntilAddress); }
internal ReadAsyncResult(Status status, Output output) { this.status = status; this.output = output; readAsyncInternal = default; }
/// <inheritdoc /> public virtual void GlobalAfterEnteringState <Key, Value>(SystemState next, FasterKV <Key, Value> faster) { }
/// <inheritdoc /> public override void GlobalBeforeEnteringState <Key, Value>(SystemState next, FasterKV <Key, Value> faster) { switch (next.Phase) { case Phase.PREPARE: faster._hybridLogCheckpoint = faster._lastSnapshotCheckpoint; base.GlobalBeforeEnteringState(next, faster); faster._hybridLogCheckpoint.info.startLogicalAddress = faster.hlog.FlushedUntilAddress; faster._hybridLogCheckpoint.prevVersion = next.Version; break; case Phase.WAIT_FLUSH: base.GlobalBeforeEnteringState(next, faster); faster._hybridLogCheckpoint.info.finalLogicalAddress = 0; faster.ObtainCurrentTailAddress(ref faster._hybridLogCheckpoint.info.finalLogicalAddress); if (faster._hybridLogCheckpoint.deltaLog == null) { faster._hybridLogCheckpoint.deltaFileDevice = faster.checkpointManager.GetDeltaLogDevice(faster._hybridLogCheckpointToken); faster._hybridLogCheckpoint.deltaFileDevice.Initialize(-1); faster._hybridLogCheckpoint.deltaLog = new DeltaLog(faster._hybridLogCheckpoint.deltaFileDevice, faster.hlog.LogPageSizeBits, -1); faster._hybridLogCheckpoint.deltaLog.InitializeForWrites(faster.hlog.bufferPool); } faster.hlog.AsyncFlushDeltaToDevice( faster._hybridLogCheckpoint.info.startLogicalAddress, faster._hybridLogCheckpoint.info.finalLogicalAddress, faster._lastSnapshotCheckpoint.info.finalLogicalAddress, faster._hybridLogCheckpoint.prevVersion, faster._hybridLogCheckpoint.deltaLog); break; case Phase.PERSISTENCE_CALLBACK: faster._hybridLogCheckpoint.info.flushedLogicalAddress = faster.hlog.FlushedUntilAddress; CollectMetadata(next, faster); faster.WriteHybridLogIncrementalMetaInfo(faster._hybridLogCheckpoint.deltaLog); faster._hybridLogCheckpoint.info.deltaTailAddress = faster._hybridLogCheckpoint.deltaLog.TailAddress; faster._lastSnapshotCheckpoint = faster._hybridLogCheckpoint.Transfer(); faster._hybridLogCheckpoint.Dispose(); break; } }
/// <summary> /// Constructor /// </summary> /// <param name="fht"></param> /// <param name="allocator"></param> public LogAccessor(FasterKV <Key, Value, Input, Output, Context, Functions> fht, AllocatorBase <Key, Value> allocator) { this.fht = fht; this.allocator = allocator; }
/// <summary> /// Constructor /// </summary> /// <param name="fht"></param> /// <param name="allocator"></param> public LogAccessor(FasterKV <Key, Value> fht, AllocatorBase <Key, Value> allocator) { this.fht = fht; this.allocator = allocator; }
/// <inheritdoc /> public ValueTask OnThreadState <Key, Value, Input, Output, Context, Functions>( SystemState current, SystemState prev, FasterKV <Key, Value, Input, Output, Context, Functions> faster, FasterKV <Key, Value, Input, Output, Context, Functions> .FasterExecutionContext ctx, ClientSession <Key, Value, Input, Output, Context, Functions> clientSession, bool async = true, CancellationToken token = default) where Key : new() where Value : new() where Functions : IFunctions <Key, Value, Input, Output, Context> { switch (current.phase) { case Phase.PREPARE: if (ctx != null) { if (!ctx.markers[EpochPhaseIdx.Prepare]) { if (!faster.RelaxedCPR) { faster.AcquireSharedLatchesForAllPendingRequests(ctx); } ctx.markers[EpochPhaseIdx.Prepare] = true; } faster.epoch.Mark(EpochPhaseIdx.Prepare, current.version); } if (faster.epoch.CheckIsComplete(EpochPhaseIdx.Prepare, current.version)) { faster.GlobalStateMachineStep(current); } break; case Phase.IN_PROGRESS: if (ctx != null) { // Need to be very careful here as threadCtx is changing var _ctx = prev.phase == Phase.IN_PROGRESS ? ctx.prevCtx : ctx; if (!_ctx.markers[EpochPhaseIdx.InProgress]) { faster.AtomicSwitch(ctx, ctx.prevCtx, _ctx.version); faster.InitContext(ctx, ctx.prevCtx.guid, ctx.prevCtx.serialNum); // Has to be prevCtx, not ctx ctx.prevCtx.markers[EpochPhaseIdx.InProgress] = true; } faster.epoch.Mark(EpochPhaseIdx.InProgress, current.version); } // Has to be prevCtx, not ctx if (faster.epoch.CheckIsComplete(EpochPhaseIdx.InProgress, current.version)) { faster.GlobalStateMachineStep(current); } break; case Phase.WAIT_PENDING: if (ctx != null) { if (!faster.RelaxedCPR && !ctx.prevCtx.markers[EpochPhaseIdx.WaitPending]) { if (ctx.prevCtx.HasNoPendingRequests) { ctx.prevCtx.markers[EpochPhaseIdx.WaitPending] = true; } else { break; } } faster.epoch.Mark(EpochPhaseIdx.WaitPending, current.version); } if (faster.epoch.CheckIsComplete(EpochPhaseIdx.WaitPending, current.version)) { faster.GlobalStateMachineStep(current); } break; case Phase.REST: break; } return(default);
/// <inheritdoc /> public void GlobalAfterEnteringState <Key, Value, Input, Output, Context, Functions>(SystemState next, FasterKV <Key, Value, Input, Output, Context, Functions> faster) where Key : new() where Value : new() where Functions : IFunctions <Key, Value, Input, Output, Context> { foreach (var task in tasks) { task.GlobalAfterEnteringState(next, faster); } }
/// <inheritdoc /> public async ValueTask OnThreadState <Key, Value, Input, Output, Context, Functions>(SystemState current, SystemState prev, FasterKV <Key, Value, Input, Output, Context, Functions> faster, FasterKV <Key, Value, Input, Output, Context, Functions> .FasterExecutionContext ctx, ClientSession <Key, Value, Input, Output, Context, Functions> clientSession, bool async = true, CancellationToken token = default) where Key : new() where Value : new() where Functions : IFunctions <Key, Value, Input, Output, Context> { if (current.phase != Phase.WAIT_INDEX_CHECKPOINT) { return; } if (async && !faster.IsIndexFuzzyCheckpointCompleted()) { clientSession?.UnsafeSuspendThread(); await faster.IsIndexFuzzyCheckpointCompletedAsync(token); clientSession?.UnsafeResumeThread(); } faster.GlobalStateMachineStep(current); }
/// <inheritdoc /> public override void GlobalBeforeEnteringState <Key, Value>(SystemState next, FasterKV <Key, Value> faster) { switch (next.Phase) { case Phase.PREPARE: faster._lastSnapshotCheckpoint.Dispose(); base.GlobalBeforeEnteringState(next, faster); faster._hybridLogCheckpoint.info.startLogicalAddress = faster.hlog.FlushedUntilAddress; faster._hybridLogCheckpoint.info.useSnapshotFile = 1; break; case Phase.WAIT_FLUSH: base.GlobalBeforeEnteringState(next, faster); faster.ObtainCurrentTailAddress(ref faster._hybridLogCheckpoint.info.finalLogicalAddress); faster._hybridLogCheckpoint.info.snapshotFinalLogicalAddress = faster._hybridLogCheckpoint.info.finalLogicalAddress; faster._hybridLogCheckpoint.snapshotFileDevice = faster.checkpointManager.GetSnapshotLogDevice(faster._hybridLogCheckpointToken); faster._hybridLogCheckpoint.snapshotFileObjectLogDevice = faster.checkpointManager.GetSnapshotObjectLogDevice(faster._hybridLogCheckpointToken); faster._hybridLogCheckpoint.snapshotFileDevice.Initialize(faster.hlog.GetSegmentSize()); faster._hybridLogCheckpoint.snapshotFileObjectLogDevice.Initialize(-1); long startPage = faster.hlog.GetPage(faster._hybridLogCheckpoint.info.startLogicalAddress); long endPage = faster.hlog.GetPage(faster._hybridLogCheckpoint.info.finalLogicalAddress); if (faster._hybridLogCheckpoint.info.finalLogicalAddress > faster.hlog.GetStartLogicalAddress(endPage)) { endPage++; } // We are writing pages outside epoch protection, so callee should be able to // handle corrupted or unexpected concurrent page changes during the flush, e.g., by // resuming epoch protection if necessary. Correctness is not affected as we will // only read safe pages during recovery. faster.hlog.AsyncFlushPagesToDevice( startPage, endPage, faster._hybridLogCheckpoint.info.finalLogicalAddress, faster._hybridLogCheckpoint.snapshotFileDevice, faster._hybridLogCheckpoint.snapshotFileObjectLogDevice, out faster._hybridLogCheckpoint.flushedSemaphore); break; case Phase.PERSISTENCE_CALLBACK: // update flushed-until address to the latest faster._hybridLogCheckpoint.info.flushedLogicalAddress = faster.hlog.FlushedUntilAddress; base.GlobalBeforeEnteringState(next, faster); faster._lastSnapshotCheckpoint = faster._hybridLogCheckpoint.Transfer(); break; default: base.GlobalBeforeEnteringState(next, faster); break; } }