예제 #1
0
파일: FASTER.cs 프로젝트: zhoubass/FASTER
        /// <summary>
        /// Create FASTER instance
        /// </summary>
        /// <param name="size">Size of core index (#cache lines)</param>
        /// <param name="comparer">FASTER equality comparer for key</param>
        /// <param name="variableLengthStructSettings"></param>
        /// <param name="functions">Callback functions</param>
        /// <param name="logSettings">Log settings</param>
        /// <param name="checkpointSettings">Checkpoint settings</param>
        /// <param name="serializerSettings">Serializer settings</param>
        public FasterKV(long size, Functions functions, LogSettings logSettings, CheckpointSettings checkpointSettings = null, SerializerSettings <Key, Value> serializerSettings = null, IFasterEqualityComparer <Key> comparer = null, VariableLengthStructSettings <Key, Value> variableLengthStructSettings = null)
        {
            if (comparer != null)
            {
                this.comparer = comparer;
            }
            else
            {
                if (typeof(IFasterEqualityComparer <Key>).IsAssignableFrom(typeof(Key)))
                {
                    this.comparer = new Key() as IFasterEqualityComparer <Key>;
                }
                else
                {
                    Console.WriteLine("***WARNING*** Creating default FASTER key equality comparer based on potentially slow EqualityComparer<Key>.Default. To avoid this, provide a comparer (IFasterEqualityComparer<Key>) as an argument to FASTER's constructor, or make Key implement the interface IFasterEqualityComparer<Key>");
                    this.comparer = FasterEqualityComparer <Key> .Default;
                }
            }

            if (checkpointSettings == null)
            {
                checkpointSettings = new CheckpointSettings();
            }

            if (checkpointSettings.CheckpointDir != null && checkpointSettings.CheckpointManager != null)
            {
                throw new FasterException("Specify either CheckpointManager or CheckpointDir for CheckpointSettings, not both");
            }

            checkpointManager = checkpointSettings.CheckpointManager ?? new LocalCheckpointManager(checkpointSettings.CheckpointDir ?? "");

            FoldOverSnapshot = checkpointSettings.CheckPointType == core.CheckpointType.FoldOver;
            CopyReadsToTail  = logSettings.CopyReadsToTail;
            this.functions   = functions;

            if (logSettings.ReadCacheSettings != null)
            {
                CopyReadsToTail = false;
                UseReadCache    = true;
            }

            if (Utility.IsBlittable <Key>() && Utility.IsBlittable <Value>())
            {
                if (variableLengthStructSettings != null)
                {
                    hlog = new VariableLengthBlittableAllocator <Key, Value>(logSettings, variableLengthStructSettings, this.comparer, null, epoch);
                    Log  = new LogAccessor <Key, Value, Input, Output, Context, Functions>(this, hlog);
                    if (UseReadCache)
                    {
                        readcache = new VariableLengthBlittableAllocator <Key, Value>(
                            new LogSettings
                        {
                            PageSizeBits    = logSettings.ReadCacheSettings.PageSizeBits,
                            MemorySizeBits  = logSettings.ReadCacheSettings.MemorySizeBits,
                            SegmentSizeBits = logSettings.ReadCacheSettings.MemorySizeBits,
                            MutableFraction = 1 - logSettings.ReadCacheSettings.SecondChanceFraction
                        }, variableLengthStructSettings, this.comparer, ReadCacheEvict, epoch);
                        readcache.Initialize();
                        ReadCache = new LogAccessor <Key, Value, Input, Output, Context, Functions>(this, readcache);
                    }
                }
                else
                {
                    hlog = new BlittableAllocator <Key, Value>(logSettings, this.comparer, null, epoch);
                    Log  = new LogAccessor <Key, Value, Input, Output, Context, Functions>(this, hlog);
                    if (UseReadCache)
                    {
                        readcache = new BlittableAllocator <Key, Value>(
                            new LogSettings
                        {
                            PageSizeBits    = logSettings.ReadCacheSettings.PageSizeBits,
                            MemorySizeBits  = logSettings.ReadCacheSettings.MemorySizeBits,
                            SegmentSizeBits = logSettings.ReadCacheSettings.MemorySizeBits,
                            MutableFraction = 1 - logSettings.ReadCacheSettings.SecondChanceFraction
                        }, this.comparer, ReadCacheEvict, epoch);
                        readcache.Initialize();
                        ReadCache = new LogAccessor <Key, Value, Input, Output, Context, Functions>(this, readcache);
                    }
                }
            }
            else
            {
                WriteDefaultOnDelete = true;

                hlog = new GenericAllocator <Key, Value>(logSettings, serializerSettings, this.comparer, null, epoch);
                Log  = new LogAccessor <Key, Value, Input, Output, Context, Functions>(this, hlog);
                if (UseReadCache)
                {
                    readcache = new GenericAllocator <Key, Value>(
                        new LogSettings
                    {
                        PageSizeBits    = logSettings.ReadCacheSettings.PageSizeBits,
                        MemorySizeBits  = logSettings.ReadCacheSettings.MemorySizeBits,
                        SegmentSizeBits = logSettings.ReadCacheSettings.MemorySizeBits,
                        MutableFraction = 1 - logSettings.ReadCacheSettings.SecondChanceFraction
                    }, serializerSettings, this.comparer, ReadCacheEvict, epoch);
                    readcache.Initialize();
                    ReadCache = new LogAccessor <Key, Value, Input, Output, Context, Functions>(this, readcache);
                }
            }

            hlog.Initialize();

            sectorSize = (int)logSettings.LogDevice.SectorSize;
            Initialize(size, sectorSize);

            _systemState         = default;
            _systemState.phase   = Phase.REST;
            _systemState.version = 1;
            _checkpointType      = CheckpointType.HYBRID_LOG_ONLY;
        }
예제 #2
0
 /// <summary>
 /// Compare two <see cref="SystemState"/>s for equality
 /// </summary>
 internal static bool Equal(SystemState s1, SystemState s2)
 {
     return(s1.Word == s2.Word);
 }
예제 #3
0
 /// <summary>
 /// Compare the current <see cref="SystemState"/> to <paramref name="other"/> for equality
 /// </summary>
 private bool Equals(SystemState other)
 {
     return(Word == other.Word);
 }
예제 #4
0
 public static bool Equal(SystemState s1, SystemState s2)
 {
     return(s1.word == s2.word);
 }
예제 #5
0
 internal static void RemoveIntermediate(ref SystemState state)
 {
     state.Phase &= ~Phase.INTERMEDIATE;
 }
예제 #6
0
        protected bool GlobalMoveToNextState(SystemState currentState, SystemState nextState, ref long context)
        {
            var intermediateState = SystemState.Make(Phase.INTERMEDIATE, currentState.version);

            // Move from S1 to I
            if (MakeTransition(currentState, intermediateState))
            {
                // Acquired ownership to make the transition from S1 to S2
                switch (nextState.phase)
                {
                case Phase.PREP_INDEX_CHECKPOINT:
                {
                    _checkpointType = (CheckpointType)context;
                    switch (_checkpointType)
                    {
                    case CheckpointType.INDEX_ONLY:
                    {
                        _indexCheckpointToken = Guid.NewGuid();
                        InitializeIndexCheckpoint(_indexCheckpointToken);
                        break;
                    }

                    case CheckpointType.FULL:
                    {
                        var fullCheckpointToken = Guid.NewGuid();
                        _indexCheckpointToken     = fullCheckpointToken;
                        _hybridLogCheckpointToken = fullCheckpointToken;
                        InitializeIndexCheckpoint(_indexCheckpointToken);
                        InitializeHybridLogCheckpoint(_hybridLogCheckpointToken, currentState.version);
                        break;
                    }

                    default:
                        throw new Exception();
                    }

                    ObtainCurrentTailAddress(ref _indexCheckpoint.info.startLogicalAddress);

                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.INDEX_CHECKPOINT:
                {
                    TakeIndexFuzzyCheckpoint();

                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.PREPARE:
                {
                    switch (currentState.phase)
                    {
                    case Phase.REST:
                    {
                        _checkpointType = (CheckpointType)context;
                        Debug.Assert(_checkpointType == CheckpointType.HYBRID_LOG_ONLY);
                        _hybridLogCheckpointToken = Guid.NewGuid();
                        InitializeHybridLogCheckpoint(_hybridLogCheckpointToken, currentState.version);
                        break;
                    }

                    case Phase.PREP_INDEX_CHECKPOINT:
                    {
                        TakeIndexFuzzyCheckpoint();
                        break;
                    }

                    default:
                        throw new Exception();
                    }

                    ObtainCurrentTailAddress(ref _hybridLogCheckpoint.info.startLogicalAddress);

                    if (!Constants.kFoldOverSnapshot)
                    {
                        _hybridLogCheckpoint.info.flushedLogicalAddress = hlog.FlushedUntilAddress;
                        _hybridLogCheckpoint.info.useSnapshotFile       = 1;
                    }

                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.IN_PROGRESS:
                {
                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.WAIT_PENDING:
                {
                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.WAIT_FLUSH:
                {
                    if (_checkpointType == CheckpointType.FULL)
                    {
                        _indexCheckpoint.info.num_buckets = overflowBucketsAllocator.GetMaxValidAddress();
                        ObtainCurrentTailAddress(ref _indexCheckpoint.info.finalLogicalAddress);
                        WriteIndexMetaFile();
                    }

                    if (Constants.kFoldOverSnapshot)
                    {
                        hlog.ShiftReadOnlyToTail(out long tailAddress);

                        _hybridLogCheckpoint.info.finalLogicalAddress = tailAddress;
                    }
                    else
                    {
                        ObtainCurrentTailAddress(ref _hybridLogCheckpoint.info.finalLogicalAddress);

                        _hybridLogCheckpoint.snapshotFileDevice = FasterFactory.CreateLogDevice
                                                                      (DirectoryConfiguration.GetHybridLogCheckpointFileName(_hybridLogCheckpointToken));
                        _hybridLogCheckpoint.snapshotFileObjectLogDevice = FasterFactory.CreateObjectLogDevice
                                                                               (DirectoryConfiguration.GetHybridLogCheckpointFileName(_hybridLogCheckpointToken));

                        long startPage = hlog.GetPage(_hybridLogCheckpoint.info.flushedLogicalAddress);
                        long endPage   = hlog.GetPage(_hybridLogCheckpoint.info.finalLogicalAddress);
                        if (_hybridLogCheckpoint.info.finalLogicalAddress > hlog.GetStartLogicalAddress(endPage))
                        {
                            endPage++;
                        }

                        new Thread(() =>
                                   hlog.AsyncFlushPagesToDevice(startPage,
                                                                endPage,
                                                                _hybridLogCheckpoint.snapshotFileDevice,
                                                                _hybridLogCheckpoint.snapshotFileObjectLogDevice,
                                                                out _hybridLogCheckpoint.flushed)).Start();
                    }

                    WriteHybridLogMetaInfo();

                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.PERSISTENCE_CALLBACK:
                {
                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.GC:
                {
                    var tmp = hlog.BeginAddress;
                    hlog.BeginAddress = context;
                    context           = tmp;

                    int numChunks = (int)(state[resizeInfo.version].size / Constants.kSizeofChunk);
                    if (numChunks == 0)
                    {
                        numChunks = 1;                         // at least one chunk
                    }
                    numPendingChunksToBeGCed = numChunks;
                    gcStatus = new long[numChunks];

                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.PREPARE_GROW:
                {
                    // Note that the transition must be done before bumping epoch here!
                    MakeTransition(intermediateState, nextState);
                    epoch.BumpCurrentEpoch(() =>
                        {
                            long _context = 0;
                            GlobalMoveToNextState(nextState, SystemState.Make(Phase.IN_PROGRESS_GROW, nextState.version), ref _context);
                        });
                    break;
                }

                case Phase.IN_PROGRESS_GROW:
                {
                    // Set up the transition to new version of HT
                    int numChunks = (int)(state[resizeInfo.version].size / Constants.kSizeofChunk);
                    if (numChunks == 0)
                    {
                        numChunks = 1;                         // at least one chunk
                    }
                    numPendingChunksToBeSplit = numChunks;
                    splitStatus = new long[numChunks];

                    Initialize(1 - resizeInfo.version, state[resizeInfo.version].size * 2, hlog.GetSectorSize());

                    resizeInfo.version = 1 - resizeInfo.version;

                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.REST:
                {
                    switch (_checkpointType)
                    {
                    case CheckpointType.INDEX_ONLY:
                    {
                        _indexCheckpoint.info.num_buckets = overflowBucketsAllocator.GetMaxValidAddress();
                        ObtainCurrentTailAddress(ref _indexCheckpoint.info.finalLogicalAddress);
                        WriteIndexMetaFile();
                        _indexCheckpoint.Reset();
                        break;
                    }

                    case CheckpointType.FULL:
                    {
                        _indexCheckpoint.Reset();
                        _hybridLogCheckpoint.Reset();
                        break;
                    }

                    case CheckpointType.HYBRID_LOG_ONLY:
                    {
                        _hybridLogCheckpoint.Reset();
                        break;
                    }

                    case CheckpointType.NONE:
                        break;

                    default:
                        throw new Exception();
                    }

                    _checkpointType = CheckpointType.NONE;

                    MakeTransition(intermediateState, nextState);
                    break;
                }
                }
                return(true);
            }
            else
            {
                return(false);
            }
        }
예제 #7
0
        protected bool GlobalMoveToNextCheckpointState(SystemState currentState)
        {
            long context = 0;

            return(GlobalMoveToNextState(currentState, GetNextState(currentState, _checkpointType), ref context));
        }
예제 #8
0
        /// <inheritdoc />
        public virtual 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:
                if (faster._hybridLogCheckpointToken == default)
                {
                    faster._hybridLogCheckpointToken = Guid.NewGuid();
                    faster.InitializeHybridLogCheckpoint(faster._hybridLogCheckpointToken, 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;
                break;

            case Phase.PERSISTENCE_CALLBACK:
                // 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);
                }

                if (faster._activeSessions != null)
                {
                    // write dormant sessions to checkpoint
                    foreach (var kvp in faster._activeSessions)
                    {
                        faster.AtomicSwitch(kvp.Value.ctx, kvp.Value.ctx.prevCtx, next.version - 1);
                    }
                }

                faster.WriteHybridLogMetaInfo();
                break;

            case Phase.REST:
                faster._hybridLogCheckpointToken = default;
                faster._hybridLogCheckpoint.Reset();
                var nextTcs = new TaskCompletionSource <LinkedCheckpointInfo>(TaskCreationOptions.RunContinuationsAsynchronously);
                faster.checkpointTcs.SetResult(new LinkedCheckpointInfo {
                    NextTask = nextTcs.Task
                });
                faster.checkpointTcs = nextTcs;
                break;
            }
        }
예제 #9
0
 /// <inheritdoc />
 public virtual 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>
 {
 }
예제 #10
0
        private SystemState FastForwardToCurrentCycle(SystemState currentThreadState, SystemState currentGlobalState)
        {
            var startState = StartOfCurrentCycle(currentGlobalState);

            if (currentThreadState.version < startState.version ||
                currentThreadState.version == startState.version && currentThreadState.phase < startState.phase)
            {
                return(startState);
            }

            return(currentThreadState);
        }
예제 #11
0
 private SystemState StartOfCurrentCycle(SystemState currentGlobalState)
 {
     return(currentGlobalState.phase <= Phase.REST
         ? SystemState.Make(Phase.REST, currentGlobalState.version - 1)
         : SystemState.Make(Phase.REST, currentGlobalState.version));
 }
예제 #12
0
파일: Checkpoint.cs 프로젝트: vbegin/FASTER
        private bool GlobalMoveToNextState(SystemState currentState, SystemState nextState, ref long context)
        {
            var intermediateState = SystemState.Make(Phase.INTERMEDIATE, currentState.version);

            // Move from S1 to I
            if (MakeTransition(currentState, intermediateState))
            {
                // Acquired ownership to make the transition from S1 to S2
                switch (nextState.phase)
                {
                case Phase.PREP_INDEX_CHECKPOINT:
                {
                    _checkpointType = (CheckpointType)context;

                    switch (_checkpointType)
                    {
                    case CheckpointType.INDEX_ONLY:
                    {
                        _indexCheckpointToken = Guid.NewGuid();
                        InitializeIndexCheckpoint(_indexCheckpointToken);
                        break;
                    }

                    case CheckpointType.FULL:
                    {
                        var fullCheckpointToken = Guid.NewGuid();
                        _indexCheckpointToken     = fullCheckpointToken;
                        _hybridLogCheckpointToken = fullCheckpointToken;
                        InitializeIndexCheckpoint(_indexCheckpointToken);
                        InitializeHybridLogCheckpoint(_hybridLogCheckpointToken, currentState.version);
                        break;
                    }

                    default:
                        throw new FasterException();
                    }

                    ObtainCurrentTailAddress(ref _indexCheckpoint.info.startLogicalAddress);

                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.INDEX_CHECKPOINT:
                {
                    if (UseReadCache && this.ReadCache.BeginAddress != this.ReadCache.TailAddress)
                    {
                        throw new FasterException("Index checkpoint with read cache is not supported");
                    }
                    TakeIndexFuzzyCheckpoint();

                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.PREPARE:
                {
                    switch (currentState.phase)
                    {
                    case Phase.REST:
                    {
                        _checkpointType = (CheckpointType)context;

                        Debug.Assert(_checkpointType == CheckpointType.HYBRID_LOG_ONLY);
                        _hybridLogCheckpointToken = Guid.NewGuid();
                        InitializeHybridLogCheckpoint(_hybridLogCheckpointToken, currentState.version);
                        break;
                    }

                    case Phase.PREP_INDEX_CHECKPOINT:
                    {
                        if (UseReadCache && this.ReadCache.BeginAddress != this.ReadCache.TailAddress)
                        {
                            throw new FasterException("Index checkpoint with read cache is not supported");
                        }
                        TakeIndexFuzzyCheckpoint();
                        break;
                    }

                    default:
                        throw new FasterException();
                    }

                    ObtainCurrentTailAddress(ref _hybridLogCheckpoint.info.startLogicalAddress);

                    if (!FoldOverSnapshot)
                    {
                        _hybridLogCheckpoint.info.flushedLogicalAddress = hlog.FlushedUntilAddress;
                        _hybridLogCheckpoint.info.useSnapshotFile       = 1;
                    }

                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.IN_PROGRESS:
                {
                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.WAIT_PENDING:
                {
                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.WAIT_FLUSH:
                {
                    if (_checkpointType == CheckpointType.FULL)
                    {
                        _indexCheckpoint.info.num_buckets = overflowBucketsAllocator.GetMaxValidAddress();
                        ObtainCurrentTailAddress(ref _indexCheckpoint.info.finalLogicalAddress);
                    }

                    _hybridLogCheckpoint.info.headAddress  = hlog.HeadAddress;
                    _hybridLogCheckpoint.info.beginAddress = hlog.BeginAddress;

                    var seg = hlog.GetSegmentOffsets();
                    if (seg != null)
                    {
                        _hybridLogCheckpoint.info.objectLogSegmentOffsets = new long[seg.Length];
                        Array.Copy(seg, _hybridLogCheckpoint.info.objectLogSegmentOffsets, seg.Length);
                    }

                    if (FoldOverSnapshot)
                    {
                        hlog.ShiftReadOnlyToTail(out long tailAddress, out _hybridLogCheckpoint.flushedSemaphore);
                        _hybridLogCheckpoint.info.finalLogicalAddress = tailAddress;
                    }
                    else
                    {
                        ObtainCurrentTailAddress(ref _hybridLogCheckpoint.info.finalLogicalAddress);

                        _hybridLogCheckpoint.snapshotFileDevice          = checkpointManager.GetSnapshotLogDevice(_hybridLogCheckpointToken);
                        _hybridLogCheckpoint.snapshotFileObjectLogDevice = checkpointManager.GetSnapshotObjectLogDevice(_hybridLogCheckpointToken);
                        _hybridLogCheckpoint.snapshotFileDevice.Initialize(hlog.GetSegmentSize());
                        _hybridLogCheckpoint.snapshotFileObjectLogDevice.Initialize(-1);

                        long startPage = hlog.GetPage(_hybridLogCheckpoint.info.flushedLogicalAddress);
                        long endPage   = hlog.GetPage(_hybridLogCheckpoint.info.finalLogicalAddress);
                        if (_hybridLogCheckpoint.info.finalLogicalAddress > hlog.GetStartLogicalAddress(endPage))
                        {
                            endPage++;
                        }

                        // This can be run on a new thread if we want to immediately parallelize
                        // the rest of the log flush
                        hlog.AsyncFlushPagesToDevice(
                            startPage,
                            endPage,
                            _hybridLogCheckpoint.info.finalLogicalAddress,
                            _hybridLogCheckpoint.snapshotFileDevice,
                            _hybridLogCheckpoint.snapshotFileObjectLogDevice,
                            out _hybridLogCheckpoint.flushedSemaphore);
                    }


                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.PERSISTENCE_CALLBACK:
                {
                    if (_activeSessions != null)
                    {
                        // write dormant sessions to checkpoint
                        foreach (var kvp in _activeSessions)
                        {
                            AtomicSwitch(kvp.Value.ctx, kvp.Value.ctx.prevCtx, currentState.version - 1);
                        }
                    }
                    WriteHybridLogMetaInfo();

                    if (_checkpointType == CheckpointType.FULL)
                    {
                        WriteIndexMetaInfo();
                    }

                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.PREPARE_GROW:
                {
                    // Note that the transition must be done before bumping epoch here!
                    MakeTransition(intermediateState, nextState);
                    epoch.BumpCurrentEpoch(() =>
                        {
                            long _context = 0;
                            GlobalMoveToNextState(nextState, SystemState.Make(Phase.IN_PROGRESS_GROW, nextState.version), ref _context);
                        });
                    break;
                }

                case Phase.IN_PROGRESS_GROW:
                {
                    // Set up the transition to new version of HT
                    int numChunks = (int)(state[resizeInfo.version].size / Constants.kSizeofChunk);
                    if (numChunks == 0)
                    {
                        numChunks = 1;                         // at least one chunk
                    }
                    numPendingChunksToBeSplit = numChunks;
                    splitStatus = new long[numChunks];

                    Initialize(1 - resizeInfo.version, state[resizeInfo.version].size * 2, sectorSize);

                    resizeInfo.version = 1 - resizeInfo.version;

                    MakeTransition(intermediateState, nextState);
                    break;
                }

                case Phase.REST:
                {
                    switch (_checkpointType)
                    {
                    case CheckpointType.INDEX_ONLY:
                    {
                        _indexCheckpoint.info.num_buckets = overflowBucketsAllocator.GetMaxValidAddress();
                        ObtainCurrentTailAddress(ref _indexCheckpoint.info.finalLogicalAddress);
                        WriteIndexMetaInfo();
                        _indexCheckpoint.Reset();
                        break;
                    }

                    case CheckpointType.FULL:
                    {
                        _indexCheckpoint.Reset();
                        _hybridLogCheckpoint.Reset();
                        break;
                    }

                    case CheckpointType.HYBRID_LOG_ONLY:
                    {
                        _hybridLogCheckpoint.Reset();
                        break;
                    }

                    default:
                        throw new FasterException();
                    }

                    var nextTcs = new TaskCompletionSource <LinkedCheckpointInfo>(TaskCreationOptions.RunContinuationsAsynchronously);
                    checkpointTcs.SetResult(new LinkedCheckpointInfo {
                            NextTask = nextTcs.Task
                        });
                    checkpointTcs = nextTcs;

                    MakeTransition(intermediateState, nextState);
                    break;
                }
                }
                return(true);
            }
            else
            {
                return(false);
            }
        }
예제 #13
0
 /// <inheritdoc />
 public abstract SystemState NextState(SystemState start);
예제 #14
0
 /// <summary>
 /// Check whether thread is in same cycle compared to current systemState
 /// </summary>
 /// <param name="ctx"></param>
 /// <param name="threadState"></param>
 /// <returns></returns>
 internal bool SameCycle <Input, Output, Context>(FasterExecutionContext <Input, Output, Context> ctx, SystemState threadState)
 {
     if (ctx == null)
     {
         var _systemState = SystemState.Copy(ref systemState);
         SystemState.RemoveIntermediate(ref _systemState);
         return(StartOfCurrentCycle(threadState).Version == StartOfCurrentCycle(_systemState).Version);
     }
     return(ctx.threadStateMachine == currentSyncStateMachine);
 }
예제 #15
0
 /// <inheritdoc />
 public virtual void GlobalAfterEnteringState <Key, Value>(SystemState next,
                                                           FasterKV <Key, Value> faster)
     where Key : new()
     where Value : new()
 {
 }
예제 #16
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();
            }
        }
 /// <inheritdoc />
 public void GlobalAfterEnteringState <Key, Value>(
     SystemState next,
     FasterKV <Key, Value> faster)
 {
 }
예제 #18
0
        /// <inheritdoc />
        public ValueTask 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,
            bool async = true,
            CancellationToken token = default)
            where Key : new()
            where Value : new()
            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;

                    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);
예제 #19
0
        protected void HandleCheckpointingPhases()
        {
            var previousState = SystemState.Make(threadCtx.phase, threadCtx.version);
            var finalState    = SystemState.Copy(ref _systemState);

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

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

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

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

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

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

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

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

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

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

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

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

                        InitLocalContext(ref threadCtx, prevThreadCtx.guid);

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

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

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

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

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

                        if (notify)
                        {
                            WriteHybridLogContextInfo();

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

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

                case Phase.PERSISTENCE_CALLBACK:
                {
                    if (!prevThreadCtx.markers[EpochPhaseIdx.PersistenceCallback])
                    {
                        // Thread local action
                        Functions.PersistenceCallback(LightEpoch.threadEntryIndex, prevThreadCtx.serialNum);

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

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

                case Phase.REST:
                {
                    break;
                }

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

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

                previousState.word = currentState.word;
            } while (previousState.word != finalState.word);
        }
예제 #20
0
 internal static SystemState MakeIntermediate(SystemState state)
 => Make(state.Phase | Phase.INTERMEDIATE, state.Version);
예제 #21
0
        protected SystemState GetNextState(SystemState start, CheckpointType type = CheckpointType.FULL)
        {
            var nextState = default(SystemState);

            nextState.word = start.word;
            switch (start.phase)
            {
            case Phase.REST:
                switch (type)
                {
                case CheckpointType.HYBRID_LOG_ONLY:
                    nextState.phase = Phase.PREPARE;
                    break;

                case CheckpointType.FULL:
                case CheckpointType.INDEX_ONLY:
                    nextState.phase = Phase.PREP_INDEX_CHECKPOINT;
                    break;
                }
                break;

            case Phase.PREP_INDEX_CHECKPOINT:
                switch (type)
                {
                case CheckpointType.INDEX_ONLY:
                    nextState.phase = Phase.INDEX_CHECKPOINT;
                    break;

                case CheckpointType.FULL:
                    nextState.phase = Phase.PREPARE;
                    break;
                }
                break;

            case Phase.INDEX_CHECKPOINT:
                nextState.phase = Phase.PREPARE;
                break;

            case Phase.PREPARE:
                nextState.phase   = Phase.IN_PROGRESS;
                nextState.version = start.version + 1;
                break;

            case Phase.IN_PROGRESS:
                nextState.phase = Phase.WAIT_PENDING;
                break;

            case Phase.WAIT_PENDING:
                nextState.phase = Phase.WAIT_FLUSH;
                break;

            case Phase.WAIT_FLUSH:
                nextState.phase = Phase.PERSISTENCE_CALLBACK;
                break;

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

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

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

            case Phase.IN_PROGRESS_GROW:
                nextState.phase = Phase.REST;
                break;
            }
            return(nextState);
        }
예제 #22
0
 public static SystemState MakeIntermediate(SystemState state)
 => Make(state.phase | Phase.INTERMEDIATE, state.version);