📄 compactor.cpp
字号:
START_ERROR:
return FALSE;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: Compactor::GetCompactingBlock()
Description: Retrieves the ID for the block currently being compacted.
Returns: Boolean indicating success.
------------------------------------------------------------------------------*/
BOOL Compactor::GetCompactingBlock(PBLOCK_ID pBlockID)
{
//----- 1. Check the parameters to insure they are legitimate -----
if(pBlockID == NULL)
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::GetCompactingBlockID() - pBlockID == NULL !!!\r\n")));
return FALSE;
}
//----- 2. Return the current block being compacted -----
*pBlockID = m_compactingBlockID;
return TRUE;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: Compactor::SetCompactingBlock()
Description: Specifies which block to use for the next compaction process.
Returns: Boolean indicating success.
------------------------------------------------------------------------------*/
BOOL Compactor::SetCompactingBlock(BLOCK_ID blockID)
{
m_compactingBlockID = blockID;
return TRUE;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: CompactorThread()
Description: Compactor thread that does the actual work necessary for coalescing
the dirty, mapped, and free sectors on the media.
Returns: Boolean indicating success.
------------------------------------------------------------------------------*/
DWORD Compactor::CompactorThread()
{
DWORD dwNumDirtySectorsFound = 0;
SECTOR_ADDR physicalSectorAddr = 0;
DWORD Result = FALSE;
for(;;)
{
//----- 1. Wait for the signal to start compaction process -----
if(WaitForSingleObject(m_hStartCompacting, INFINITE) == WAIT_FAILED)
{
DEBUGMSG(ZONE_COMPACTOR, (TEXT("FLASHDRV.DLL:CompactorThread() - Unable to wait on m_hStartCompacting event. Exiting compactor.\r\n")));
goto COMPACTOR_EXIT;
}
if (m_bEndCompactionThread)
{
DEBUGMSG(ZONE_COMPACTOR, (TEXT("FLASHDRV.DLL:CompactorThread() - Exiting compactor.\r\n")));
Result = TRUE;
goto COMPACTOR_EXIT;
}
//----- For debugging purposes, print out the statistics for this compaction request
EnterCriticalSection(&g_csFlashDevice);
RETAILMSG(1, (TEXT("FLASHDRV.DLL:------------ Starting Compaction... ------------\r\n")));
RETAILMSG(1, (TEXT(" Looking to recycle %d DIRTY sectors into FREE sectors\r\n"), m_dwFreeSectorsNeeded));
RETAILMSG(1, (TEXT(" >>> Media State Information: >>>\r\n")));
RETAILMSG(1, (TEXT(" Free Sectors = %d\r\n"), m_pSectorMgr->GetNumberOfFreeSectors() ));
RETAILMSG(1, (TEXT(" Dirty Sectors = %d\r\n"), m_pSectorMgr->GetNumDirtySectors() ));
RETAILMSG(1, (TEXT("FLASHDRV.DLL:------------------------------------------------\r\n")));
LeaveCriticalSection(&g_csFlashDevice);
for(;;)
{
DWORD dwStatus = 0;
DWORD dwBlkCount = 0;
EnterCriticalSection(&g_csFlashDevice);
//----- 2. Are we done with this compaction process? Compaction is over if the number of -----
// requested free sectors have been reclaimed or there are no more DIRTY sectors
// left to recycle.
if((m_dwFreeSectorsNeeded == 0) || (m_pSectorMgr->GetNumDirtySectors() == 0) )
{
LeaveCriticalSection( &g_csFlashDevice);
break;
}
//----- 3. Compact the next block... -----
m_compactingBlockID = GetNextCompactionBlock(m_compactingBlockID);
if ((dwBlkCount >= m_pRegion->dwNumPhysBlocks) || (m_compactingBlockID == INVALID_BLOCK_ID))
{
RETAILMSG(1, (TEXT("FLASHDRV.DLL:CompactorThread() - CompactorThread(0x%x) failed; unable to compact!!!\r\n"), m_compactingBlockID));
LeaveCriticalSection( &g_csFlashDevice);
goto COMPACTOR_EXIT;
}
//----- For debugging purposes, print out the compaction block information... -----
DEBUGMSG(ZONE_COMPACTOR, (TEXT("FLASHDRV.DLL:CompactorThread() - Compacting BLOCK %d\r\n"), m_compactingBlockID));
//----- 5. Compact the current block... -----
if((dwNumDirtySectorsFound = CompactBlock(m_compactingBlockID, USE_SECTOR_MAPPING_INFO)) == BLOCK_COMPACTION_ERROR)
{
ReportError((TEXT("FLASHDRV.DLL:CompactorThread() - Compactor::CompactBlock(%d) failed; unable to compact!!!\r\n"), m_compactingBlockID));
LeaveCriticalSection( &g_csFlashDevice);
break;
}
//----- 7. Update the number of DIRTY sectors recycled into FREE sectors while compacting this block -----
if(m_dwFreeSectorsNeeded < dwNumDirtySectorsFound)
{
m_dwFreeSectorsNeeded = 0; // Done compacting...
}else
{
m_dwFreeSectorsNeeded -= dwNumDirtySectorsFound; // Subtract # of recycled DIRTY sectors and keep going...
}
LeaveCriticalSection( &g_csFlashDevice);
}
//----- For debugging purposes, print out the compaction block information... -----
DEBUGMSG(ZONE_COMPACTOR, (TEXT("FLASHDRV.DLL >>> Compaction process complete: %d DIRTY sectors recycled \r\n"), dwNumDirtySectorsFound));
//----- 9. Signal that the compaction operation is complete... -----
if(!SetEvent(m_hCompactionComplete))
{
ReportError((TEXT("FLASHDRV.DLL:CompactorThread() - Unable to signal compaction is complete!!!\r\n")));
goto COMPACTOR_EXIT;
}
}
COMPACTOR_EXIT:
return Result;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: Compactor::CompactBlock()
Description: Compacts the specified block. Data in MAPPED sectors are relocated
to another part of the media (using the Sector Manager) and DIRTY
sectors are recycled into FREE sectors.
Notes: The treatAsDirtySectorAddr parameter is used to indicate a single
sector in the block that should be treated as DIRTY regardless of
what the mapping information states. Practically, this situation
only occurs when we are trying to re-map data to a new sector on the
media and we are NOT able to mark the old data as DIRTY. In this case,
we need to compact this block and treat the data in this sector as
DIRTY. Once compaction is complete, the old data will be deleted
from the media and recycled into a FREE sector.
Setting treatAsDirtySectorAddr == USE_SECTOR_MAPPING_INFO indicates that
the sector mapping information should be used and no sectors need to
explicitly be treated as DIRTY.
Returns: Number of DIRTY sectors recycled into FREE sectors.
------------------------------------------------------------------------------*/
DWORD Compactor::CompactBlock(BLOCK_ID compactionBlockID, SECTOR_ADDR treatAsDirtySectorAddr)
{
SECTOR_ADDR newPhysicalSectorAddr = 0;
SECTOR_ADDR physicalSectorAddr = 0;
DWORD dwNumDirtySectorsFound = 0;
DWORD i = 0;
SectorMappingInfo sectorMappingInfo;
// Record compaction in CELOG
CELOG_CompactBlock(m_bCritical, compactionBlockID);
//----- 1. Determine starting physical sector address for the specified block being compacted -----
// NOTE: If # of sectors/block is a power of 2, we can avoid a potentially expensive multiplication
// (Refer to Compactor::InitCompactor() for details...)
physicalSectorAddr = m_pSectorMgr->GetStartSectorInBlock (compactionBlockID);
// Unmark any sectors in this block that are free, since all of the sectors will be marked
// free at the end of this operation
m_pSectorMgr->UnmarkSectorsAsFree(physicalSectorAddr, m_pRegion->dwSectorsPerBlock);
//----- 2. Compact the specified block. If any data is still MAPPED, move it... -----
dwNumDirtySectorsFound = 0;
for(i=0; i<m_pRegion->dwSectorsPerBlock; i++, physicalSectorAddr++)
{
//----- 3. Read the sector mapping information for the current physical sector -----
if(!FMD.pReadSector(physicalSectorAddr, NULL, (PSectorInfo)§orMappingInfo, 1))
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::CompactBlock() - Unable to read sector mapping info for physical sector 0x%08x\r\n"), physicalSectorAddr));
goto COMPACTION_ERROR;
}
//----- 4. DIRTY sector? Unmark this sector as DIRTY (using the Sector Manager) because -----
// we are going to recycle it into a FREE sector through an erase operation.
if( IsSectorDirty(sectorMappingInfo) ||
((treatAsDirtySectorAddr != USE_SECTOR_MAPPING_INFO) && (treatAsDirtySectorAddr == physicalSectorAddr))
)
{
//----- For debugging purposes, print out the state of this sector -----
DEBUGMSG(ZONE_COMPACTOR, (TEXT("FLASHDRV.DLL >>> Physical sector 0x%08x is DIRTY\r\n"), physicalSectorAddr));
if(!m_pSectorMgr->UnmarkSectorsAsDirty(physicalSectorAddr, 1))
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::CompactBlock() - Unable to unmark physical sector 0x%08x as DIRTY\r\n"), physicalSectorAddr));
}
dwNumDirtySectorsFound++;
continue;
}
//----- 5. Data is MAPPED. Move it to another free sector on the FLASH media -----
if(IsSectorMapped(sectorMappingInfo))
{
//----- For debugging purposes, print out the state of this sector -----
DEBUGMSG(ZONE_COMPACTOR, (TEXT("FLASHDRV.DLL >>> Physical sector 0x%08x is MAPPED\r\n"), physicalSectorAddr));
// Should check if LSA is valid or not before copying the sector
// to avoid that all blocks have this invalid sector by the Compactor.
if(!m_pMap->IsValidLogicalSector(sectorMappingInfo.logicalSectorAddr))
{
ReportError((TEXT("FLASHDRV.DLL >>> Logical sector(=0x%08x) of physical sector(=0x%08x) is incorrect.\r\n"), sectorMappingInfo.logicalSectorAddr, physicalSectorAddr));
goto COMPACTION_ERROR;
}
//----- 6. Read the data into a temporary buffer -----
if(!FMD.pReadSector(physicalSectorAddr, m_pSectorData, NULL, 1))
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::CompactBlock() - Unable to read sector data for physical sector 0x%08x\r\n"), physicalSectorAddr));
goto COMPACTION_ERROR;
}
//----- Write the sector data to the media. Notice that this operation is repetitively -----
// tried ONLY if FMD.pWriteSector() fails. Unless the FLASH block we are writing to
// has just gone bad, this loop will only execute once.
for(;;)
{
//----- 7. Get a free physical sector to store the data into -----
// NOTE: Notice that the second parameter is TRUE; this forces the Sector Manager
// to give us the next FREE sector regardless of how many are left. This is
// important so that this call to the Sector Manager doesn't trigger another
// compaction.
if(!m_pSectorMgr->GetNextFreeSector(&newPhysicalSectorAddr, TRUE))
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::CompactBlock() - Unable to get next free physical sector address for writing! The media is FULL\r\n")));
goto COMPACTION_ERROR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -