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); }
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); }
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(); }
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; } } } }