Esempio n. 1
0
        // Derived class exposed API
        internal void RecoverFuzzyIndex(IndexCheckpointInfo info)
        {
            var token      = info.info.token;
            var ht_version = resizeInfo.version;

            Debug.Assert(state[ht_version].size == info.info.table_size);

            // Create devices to read from using Async API
            info.main_ht_device = Devices.CreateLogDevice(directoryConfiguration.GetPrimaryHashTableFileName(token), false);
            info.ofb_device     = Devices.CreateLogDevice(directoryConfiguration.GetOverflowBucketsFileName(token), false);

            BeginMainIndexRecovery(ht_version,
                                   info.main_ht_device,
                                   info.info.num_ht_bytes);

            overflowBucketsAllocator.Recover(
                info.ofb_device,
                info.info.num_buckets,
                info.info.num_ofb_bytes);

            // Wait until reading is complete
            IsFuzzyIndexRecoveryComplete(true);

            // close index checkpoint files appropriately
            info.main_ht_device.Close();
            info.ofb_device.Close();

            // Delete all tentative entries!
            DeleteTentativeEntries();
        }
Esempio n. 2
0
 /// <summary>
 /// Create default configuration backed by local storage at given base directory.
 /// Use Utility.ParseSize to specify sizes in familiar string notation (e.g., "4k" and "4 MB").
 /// Default index size is 64MB.
 /// </summary>
 /// <param name="baseDir">Base directory (without trailing path separator)</param>
 /// <param name="deleteDirOnDispose">Whether to delete base directory on dispose. This option prevents later recovery.</param>
 public FasterLogSettings(string baseDir, bool deleteDirOnDispose = false)
 {
     disposeDevices          = true;
     this.deleteDirOnDispose = deleteDirOnDispose;
     this.baseDir            = baseDir;
     LogDevice    = baseDir == null ? new NullDevice() : Devices.CreateLogDevice(baseDir + "/fasterlog.log", deleteOnClose: deleteDirOnDispose);
     LogCommitDir = baseDir;
 }
Esempio n. 3
0
        /// <inheritdoc />
        public IDevice Get(FileDescriptor fileInfo)
        {
            var device = Devices.CreateLogDevice(Path.Combine(baseName, fileInfo.directoryName, fileInfo.fileName), preallocateFile: preallocateFile, deleteOnClose: deleteOnClose);

            if (this.throttleLimit.HasValue)
            {
                device.ThrottleLimit = this.throttleLimit.Value;
            }
            return(device);
        }
Esempio n. 4
0
        /// <summary>
        /// Create default configuration backed by local storage at given base directory.
        /// Use Utility.ParseSize to specify sizes in familiar string notation (e.g., "4k" and "4 MB").
        /// Default index size is 64MB.
        /// </summary>
        /// <param name="baseDir">Base directory (without trailing path separator)</param>
        /// <param name="deleteDirOnDispose">Whether to delete base directory on dispose. This option prevents later recovery.</param>
        public FasterKVSettings(string baseDir, bool deleteDirOnDispose = false)
        {
            disposeDevices          = true;
            this.deleteDirOnDispose = deleteDirOnDispose;
            this.baseDir            = baseDir;

            LogDevice = baseDir == null ? new NullDevice() : Devices.CreateLogDevice(baseDir + "/hlog.log", deleteOnClose: deleteDirOnDispose);
            if ((!Utility.IsBlittable <Key>() && KeyLength == null) ||
                (!Utility.IsBlittable <Value>() && ValueLength == null))
            {
                ObjectLogDevice = baseDir == null ? new NullDevice() : Devices.CreateLogDevice(baseDir + "/hlog.obj.log", deleteOnClose: deleteDirOnDispose);
            }

            CheckpointDir = baseDir == null ? null : baseDir + "/checkpoints";
        }
Esempio n. 5
0
        private void InternalRecover(Guid indexToken, Guid hybridLogToken)
        {
            _indexCheckpoint.Recover(indexToken, directoryConfiguration);
            _hybridLogCheckpoint.Recover(hybridLogToken, directoryConfiguration);

            // Recover segment offsets for object log
            if (_hybridLogCheckpoint.info.objectLogSegmentOffsets != null)
            {
                Array.Copy(_hybridLogCheckpoint.info.objectLogSegmentOffsets,
                           hlog.GetSegmentOffsets(),
                           _hybridLogCheckpoint.info.objectLogSegmentOffsets.Length);
            }

            _indexCheckpoint.main_ht_device = Devices.CreateLogDevice(directoryConfiguration.GetPrimaryHashTableFileName(_indexCheckpoint.info.token), false);
            _indexCheckpoint.ofb_device     = Devices.CreateLogDevice(directoryConfiguration.GetOverflowBucketsFileName(_indexCheckpoint.info.token), false);

            var l1 = _indexCheckpoint.info.finalLogicalAddress;
            var l2 = _hybridLogCheckpoint.info.finalLogicalAddress;
            var v  = _hybridLogCheckpoint.info.version;

            if (l1 > l2)
            {
                throw new Exception("Cannot recover from (" + indexToken.ToString() + "," + hybridLogToken.ToString() + ") checkpoint pair!\n");
            }

            _systemState.phase   = Phase.REST;
            _systemState.version = (v + 1);

            RecoverFuzzyIndex(_indexCheckpoint);

            IsFuzzyIndexRecoveryComplete(true);

            DeleteTentativeEntries();

            if (FoldOverSnapshot)
            {
                RecoverHybridLog(_indexCheckpoint.info, _hybridLogCheckpoint.info);
            }
            else
            {
                RecoverHybridLogFromSnapshotFile(_indexCheckpoint.info, _hybridLogCheckpoint.info);
            }

            _indexCheckpoint.Reset();

            RestoreHybridLog(_hybridLogCheckpoint.info.finalLogicalAddress);
        }
Esempio n. 6
0
        private void RecoverHybridLogFromSnapshotFile(
            IndexRecoveryInfo indexRecoveryInfo,
            HybridLogRecoveryInfo recoveryInfo)
        {
            var fileStartAddress = recoveryInfo.flushedLogicalAddress;
            var fromAddress      = indexRecoveryInfo.startLogicalAddress;
            var untilAddress     = recoveryInfo.finalLogicalAddress;

            // Compute startPage and endPage
            var startPage = hlog.GetPage(fileStartAddress);
            var endPage   = hlog.GetPage(untilAddress);

            if (untilAddress > hlog.GetStartLogicalAddress(endPage))
            {
                endPage++;
            }

            // By default first page has one extra record
            var capacity                = hlog.GetCapacityNumPages();
            var recoveryDevice          = Devices.CreateLogDevice(directoryConfiguration.GetHybridLogCheckpointFileName(recoveryInfo.guid), false);
            var objectLogRecoveryDevice = Devices.CreateLogDevice(directoryConfiguration.GetHybridLogObjectCheckpointFileName(recoveryInfo.guid), false);

            recoveryDevice.Initialize(hlog.GetSegmentSize());
            objectLogRecoveryDevice.Initialize(hlog.GetSegmentSize());
            var recoveryStatus = new RecoveryStatus(capacity, startPage, endPage, untilAddress)
            {
                recoveryDevice           = recoveryDevice,
                objectLogRecoveryDevice  = objectLogRecoveryDevice,
                recoveryDevicePageOffset = startPage
            };

            // Initially issue read request for all pages that can be held in memory
            int totalPagesToRead    = (int)(endPage - startPage);
            int numPagesToReadFirst = Math.Min(capacity, totalPagesToRead);

            hlog.AsyncReadPagesFromDevice(startPage, numPagesToReadFirst, untilAddress,
                                          AsyncReadPagesCallbackForRecovery,
                                          recoveryStatus,
                                          recoveryStatus.recoveryDevicePageOffset,
                                          recoveryStatus.recoveryDevice, recoveryStatus.objectLogRecoveryDevice);


            for (long page = startPage; page < endPage; page++)
            {
                // Ensure the page is read from file
                int pageIndex = hlog.GetPageIndexForPage(page);
                while (recoveryStatus.readStatus[pageIndex] == ReadStatus.Pending)
                {
                    Thread.Sleep(10);
                }

                // Page at hand
                var startLogicalAddress = hlog.GetStartLogicalAddress(page);
                var endLogicalAddress   = hlog.GetStartLogicalAddress(page + 1);

                // Perform recovery if page in fuzzy portion of the log
                if ((fromAddress < endLogicalAddress) && (fromAddress < untilAddress))
                {
                    /*
                     * Handling corner-cases:
                     * ----------------------
                     * When fromAddress is in the middle of the page,
                     * then start recovery only from corresponding offset
                     * in page. Similarly, if untilAddress falls in the
                     * middle of the page, perform recovery only until that
                     * offset. Otherwise, scan the entire page [0, PageSize)
                     */
                    var pageFromAddress = 0L;
                    if (fromAddress > startLogicalAddress && fromAddress < endLogicalAddress)
                    {
                        pageFromAddress = hlog.GetOffsetInPage(fromAddress);
                    }

                    var pageUntilAddress = hlog.GetPageSize();
                    if (endLogicalAddress > untilAddress)
                    {
                        pageUntilAddress = hlog.GetOffsetInPage(untilAddress);
                    }

                    var physicalAddress = hlog.GetPhysicalAddress(startLogicalAddress);
                    RecoverFromPage(fromAddress, pageFromAddress, pageUntilAddress,
                                    startLogicalAddress, physicalAddress, recoveryInfo.version);
                }

                // OS thread flushes current page and issues a read request if necessary
                recoveryStatus.readStatus[pageIndex]  = ReadStatus.Pending;
                recoveryStatus.flushStatus[pageIndex] = FlushStatus.Pending;

                // Write back records from snapshot to main hybrid log
                hlog.AsyncFlushPages(page, 1, AsyncFlushPageCallbackForRecovery, recoveryStatus);
            }

            // Assert and wait until all pages have been flushed
            var done = false;

            while (!done)
            {
                done = true;
                for (long page = startPage; page < endPage; page++)
                {
                    int pageIndex = hlog.GetPageIndexForPage(page);
                    if (recoveryStatus.flushStatus[pageIndex] == FlushStatus.Pending)
                    {
                        done = false;
                        break;
                    }
                }
            }

            recoveryStatus.recoveryDevice.Close();
            recoveryStatus.objectLogRecoveryDevice.Close();
        }
Esempio n. 7
0
 /// <summary>
 /// Provide device to store snapshot of object log (required only for snapshot checkpoints)
 /// </summary>
 /// <param name="token"></param>
 /// <returns></returns>
 public IDevice GetSnapshotObjectLogDevice(Guid token)
 {
     return(Devices.CreateLogDevice(directoryConfiguration.GetObjectLogSnapshotFileName(token), false));
 }
Esempio n. 8
0
 /// <summary>
 /// Provide device to store index checkpoint (including overflow buckets)
 /// </summary>
 /// <param name="indexToken"></param>
 /// <returns></returns>
 public IDevice GetIndexDevice(Guid indexToken)
 {
     return(Devices.CreateLogDevice(directoryConfiguration.GetPrimaryHashTableFileName(indexToken), false));
 }
Esempio n. 9
0
 public void Initialize(Guid token, long _size, DirectoryConfiguration directoryConfiguration)
 {
     info.Initialize(token, _size);
     main_ht_device = Devices.CreateLogDevice(directoryConfiguration.GetPrimaryHashTableFileName(token), false);
     ofb_device     = Devices.CreateLogDevice(directoryConfiguration.GetOverflowBucketsFileName(token), false);
 }
Esempio n. 10
0
        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 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 (!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:
                {
                    var seg = hlog.GetSegmentOffsets();
                    if (seg != null)
                    {
                        _hybridLogCheckpoint.info.objectLogSegmentOffsets = new long[seg.Length];
                        Array.Copy(seg, _hybridLogCheckpoint.info.objectLogSegmentOffsets, seg.Length);
                    }
                    MakeTransition(intermediateState, nextState);
                    break;
                }

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

                    if (FoldOverSnapshot)
                    {
                        hlog.ShiftReadOnlyToTail(out long tailAddress);

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

                        _hybridLogCheckpoint.snapshotFileDevice = Devices.CreateLogDevice
                                                                      (directoryConfiguration.GetHybridLogCheckpointFileName(_hybridLogCheckpointToken), false);
                        _hybridLogCheckpoint.snapshotFileObjectLogDevice = Devices.CreateLogDevice
                                                                               (directoryConfiguration.GetHybridLogObjectCheckpointFileName(_hybridLogCheckpointToken), false);
                        _hybridLogCheckpoint.snapshotFileDevice.Initialize(hlog.GetSegmentSize());
                        _hybridLogCheckpoint.snapshotFileObjectLogDevice.Initialize(hlog.GetSegmentSize());

                        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.flushed);
                    }


                    MakeTransition(intermediateState, nextState);
                    break;
                }

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

                case Phase.GC:
                {
                    hlog.ShiftBeginAddress(context);

                    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, 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);
                        WriteIndexMetaFile();
                        WriteIndexCheckpointCompleteFile();
                        _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);
            }
        }
Esempio n. 11
0
 /// <summary>
 /// Provide device to store delta log for incremental snapshot checkpoints
 /// </summary>
 /// <param name="token"></param>
 /// <returns></returns>
 public IDevice GetDeltaLogDevice(Guid token)
 {
     return(Devices.CreateLogDevice(directoryConfiguration.GetDeltaLogFileName(token), false));
 }
 /// <inheritdoc />
 public IDevice Get(FileDescriptor fileInfo)
 {
     return(Devices.CreateLogDevice(Path.Combine(baseName, fileInfo.directoryName, fileInfo.fileName), preallocateFile: preallocateFile, deleteOnClose: deleteOnClose));
 }