Example #1
0
        private void RestoreHybridLog(long untilAddress)
        {
            var tailPage = hlog.GetPage(untilAddress);
            var headPage = default(long);

            if (untilAddress > hlog.GetStartLogicalAddress(tailPage))
            {
                headPage = (tailPage + 1) - hlog.GetHeadOffsetLagInPages();;
            }
            else
            {
                headPage = tailPage - hlog.GetHeadOffsetLagInPages();
            }
            headPage = headPage > 0 ? headPage : 0;

            var recoveryStatus = new RecoveryStatus(hlog.GetCapacityNumPages(), headPage, tailPage);

            for (int i = 0; i < recoveryStatus.capacity; i++)
            {
                recoveryStatus.readStatus[i] = ReadStatus.Done;
            }

            var numPages = 0;

            for (var page = headPage; page <= tailPage; page++)
            {
                var pageIndex = hlog.GetPageIndexForPage(page);
                recoveryStatus.readStatus[pageIndex] = ReadStatus.Pending;
                numPages++;
            }

            hlog.AsyncReadPagesFromDevice(headPage, numPages, AsyncReadPagesCallbackForRecovery, recoveryStatus);

            var done = false;

            while (!done)
            {
                done = true;
                for (long page = headPage; page <= tailPage; page++)
                {
                    int pageIndex = hlog.GetPageIndexForPage(page);
                    if (recoveryStatus.readStatus[pageIndex] == ReadStatus.Pending)
                    {
                        done = false;
                        break;
                    }
                }
            }

            var headAddress = hlog.GetStartLogicalAddress(headPage);

            if (headAddress == 0)
            {
                headAddress = Constants.kFirstValidAddress;
            }
            hlog.RecoveryReset(untilAddress, headAddress);
        }
Example #2
0
        private void RestoreHybridLog(long untilAddress, long headAddress, long beginAddress)
        {
            Debug.Assert(beginAddress <= headAddress);
            Debug.Assert(headAddress <= untilAddress);

            // Special cases: we do not load any records into memory
            if (
                (beginAddress == untilAddress) ||                                           // Empty log
                ((headAddress == untilAddress) && (hlog.GetOffsetInPage(headAddress) == 0)) // Empty in-memory page
                )
            {
                hlog.AllocatePage(hlog.GetPageIndexForAddress(headAddress));
            }
            else
            {
                var tailPage = hlog.GetPage(untilAddress);
                var headPage = hlog.GetPage(headAddress);

                var recoveryStatus = new RecoveryStatus(hlog.GetCapacityNumPages(), headPage, tailPage, untilAddress);
                for (int i = 0; i < recoveryStatus.capacity; i++)
                {
                    recoveryStatus.readStatus[i] = ReadStatus.Done;
                }

                var numPages = 0;
                for (var page = headPage; page <= tailPage; page++)
                {
                    var pageIndex = hlog.GetPageIndexForPage(page);
                    recoveryStatus.readStatus[pageIndex] = ReadStatus.Pending;
                    numPages++;
                }

                hlog.AsyncReadPagesFromDevice(headPage, numPages, untilAddress, AsyncReadPagesCallbackForRecovery, recoveryStatus);

                var done = false;
                while (!done)
                {
                    done = true;
                    for (long page = headPage; page <= tailPage; page++)
                    {
                        int pageIndex = hlog.GetPageIndexForPage(page);
                        if (recoveryStatus.readStatus[pageIndex] == ReadStatus.Pending)
                        {
                            done = false;
                            break;
                        }
                    }
                }
            }

            hlog.RecoveryReset(untilAddress, headAddress, beginAddress);
        }
Example #3
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();
        }
Example #4
0
        private void RecoverHybridLog(IndexRecoveryInfo indexRecoveryInfo,
                                      HybridLogRecoveryInfo recoveryInfo)
        {
            var fromAddress  = indexRecoveryInfo.startLogicalAddress;
            var untilAddress = recoveryInfo.finalLogicalAddress;

            var startPage = hlog.GetPage(fromAddress);
            var endPage   = hlog.GetPage(untilAddress);

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

            // By default first page has one extra record
            var capacity       = hlog.GetCapacityNumPages();
            var recoveryStatus = new RecoveryStatus(capacity, startPage, endPage, untilAddress);

            int totalPagesToRead    = (int)(endPage - startPage);
            int numPagesToReadFirst = Math.Min(capacity, totalPagesToRead);

            // Issue request to read pages as much as possible
            hlog.AsyncReadPagesFromDevice(startPage, numPagesToReadFirst, untilAddress, AsyncReadPagesCallbackForRecovery, recoveryStatus);

            for (long page = startPage; page < endPage; page++)
            {
                // Ensure page has been read into memory
                int pageIndex = hlog.GetPageIndexForPage(page);
                while (recoveryStatus.readStatus[pageIndex] == ReadStatus.Pending)
                {
                    Thread.Sleep(10);
                }

                var startLogicalAddress = hlog.GetStartLogicalAddress(page);
                var endLogicalAddress   = hlog.GetStartLogicalAddress(page + 1);

                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;

                hlog.AsyncFlushPages(page, 1, AsyncFlushPageCallbackForRecovery, recoveryStatus);
            }

            // Assert that 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;
                    }
                }
            }
        }