📄 compactor.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name: COMPACTOR.C
Abstract: Compactor module
Notes: The following module is responsible for compacting the FLASH media blocks.
A compaction operation works as follows (using psuedo-code):
foreach(physicalSector in Block b)
{
if(IsSectorMapped(physicalSector))
{
ReadSectorData(physicalSector, buffer);
newPhysicalSectorAddr = SM_GetNextFreeSector();
WriteSectorData(newPhysicalSector, buffer);
UpdateLogicalToPhysicalMapping(logicalSectorAddr, newPhysicalSectorAddr);
MarkSectorDirty(physicalSector);
}
if(IsSectorDirty(physicalSector)
{
dwNumDirtySectorsFound++;
}
}
EraseBlock(Block b);
AddFreeSectorsToSectorManager(Block b);
That is, to compact a block we just need to move any good data to another physical location
on the media and simply ignore any DIRTY physical sectors. Once the entire block has been
processed, it can then safely be erased. Notice also that all of the good data is still
retained after the ERASE operation and that data CANNOT be lost during a power-failure situation
because the old data is marked DIRTY after the data has been safely moved to another physical
sector address.
There are several important points to consider in this algorithm:
1) The compactor uses the *exact* same code to move good data to another portion of the
FLASH media as the FAL uses to write new data from the file system. Practically, this
means that the compactor queries the Sector Manager for the next FREE physical sector
when it needs to perform a WRITE operation.
2) The algorithm takes the necessary precautions to avoid *any* data loss during a
power-failure condition. In the worst case scenario, the FLASH media will end up with
two separate physical copies of the SAME data, which will be cleaned up by the FAL during
the next boot sequence.
3) The algorithm is simple. Notice that there are NO special situations or end cases to consider.
The Compactor simply moves good data to another potion of the disk (a.k.a. compacting the data)
and then erases the block.
The Compactor *always* processes FLASH blocks consecutively. Once the Compactor reaches the last
FLASH block on the media, it simply moves back to the first FLASH block and continues as necessary.
-----------------------------------------------------------------------------*/
#include "compactor.h"
//#undef ZONE_COMPACTOR
//#define ZONE_COMPACTOR 1
//#undef DEBUGMSG
//#define DEBUGMSG(cond,msg) RETAILMSG(cond,msg)
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: Compactor::InitCompactor()
Description: Initializes the compactor.
Notes: The compactor is not started by default. The caller must invoke
Compactor::StartCompactor() to start the compactor thread.
Returns: Boolean indicating success.
------------------------------------------------------------------------------*/
BOOL Compactor::Init(PFlashRegion pRegion, FileSysFal* pFal)
{
m_pRegion = pRegion;
m_pFal = pFal;
m_pSectorMgr = pFal->m_pSectorMgr;
m_pMap = pFal->m_pMap;
m_compactingBlockID = pRegion->dwStartPhysBlock;
m_bEndCompactionThread = FALSE;
if (pRegion->dwCompactBlocks < MINIMUM_FLASH_BLOCKS_TO_RESERVE)
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::InitCompactor() - Invalid number of compaction blocks in region.\r\n")));
goto INIT_ERROR;
}
//----- 1. Create the event that controls the compactor -----
if((m_hStartCompacting = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::InitCompactor() - Unable to create compactor control event object!!!\r\n")));
goto INIT_ERROR;
}
//----- 2. Create the event that signals when compacting is complete -----
if((m_hCompactionComplete = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::InitCompactor() - Unable to create compactor completion event object!!!\r\n")));
goto INIT_ERROR;
}
//----- 4. Allocate a buffer to use for moving MAPPED data during a compaction -----
if((m_pSectorData = (PBYTE)LocalAlloc(LMEM_FIXED, g_pFlashMediaInfo->dwDataBytesPerSector)) == NULL)
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::InitCompactor() - Unable to allocate memory for sector data.\r\n")));
goto INIT_ERROR;
}
//----- 5. Initialize the "nested compactions" counter. This counter is used to prevent an infinite -----
// recursion situation that can occur if WRITE operations keep failing within Compactor::CompactBlock()
m_dwNestedCompactions = 0;
//----- 6. Retrieve the ID for the block that we need to process on the next compaction -----
// NOTE: Currently, the FAL computes the block ID during system initialization and
// calls Compactor::SetCompactingBlock() appropriately. Hence, we don't need to explicitly
// store/retrieve this state information on the FLASH media.
//----- 7. Create the compactor thread -----
if((m_hCompactorThread = CreateThread(NULL, 0, ::CompactorThread, (LPVOID)this, 0, &m_dwThreadID)) == NULL)
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::InitCompactor() - Unable to create compactor thread!!!\r\n")));
goto INIT_ERROR;
}
return TRUE;
INIT_ERROR:
CloseHandle(m_hStartCompacting);
CloseHandle(m_hCompactionComplete);
CloseHandle(m_hCompactorThread);
return FALSE;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: Compactor::DeinitCompactor()
Description: Deinitializes the compactor.
Notes: The compactor is first stopped.
Returns: Boolean indicating success.
------------------------------------------------------------------------------*/
BOOL Compactor::Deinit()
{
// By entering the device critical section, we are ensuring the current compaction
// operation is complete
EnterCriticalSection(&g_csFlashDevice);
m_dwFreeSectorsNeeded = 0;
m_bEndCompactionThread = TRUE;
SetEvent (m_hStartCompacting);
LeaveCriticalSection(&g_csFlashDevice);
WaitForSingleObject(m_hCompactorThread, 10000);
//----- 2. Free all the compactor thread's system resources -----
if(LocalFree(m_pSectorData) != NULL)
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::Deinit() - Unable to free buffer used for moving MAPPED data\r\n")));
}
CloseHandle(m_hCompactionComplete);
CloseHandle(m_hStartCompacting);
CloseHandle(m_hCompactorThread);
return TRUE;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function: Compactor::StartCompactor()
Description: Starts the compactor using the specified thread priority. The
compactor thread then attempts to find the the specified number
of free sectors. If bCritical == TRUE, this function doesn't
return until the compaction stage completes.
Returns: Boolean indicating success.
------------------------------------------------------------------------------*/
BOOL Compactor::StartCompactor(DWORD dwPriority, DWORD dwFreeSectorsNeeded, BOOL bCritical)
{
//----- 1. Are there enough DIRTY sectors on the media to fulfill this request? -----
if(dwFreeSectorsNeeded > m_pSectorMgr->GetNumDirtySectors())
{
if(m_pSectorMgr->GetNumDirtySectors() == 0)
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::StartCompactor() - There aren't any DIRTY sectors left; the compactor can't be started\r\n")));
goto START_ERROR;
}else{
// Set this compaction operation to retrieve the rest of the DIRTY sectors...
dwFreeSectorsNeeded = m_pSectorMgr->GetNumDirtySectors();
}
}
//----- 2. Set the number of DIRTY sectors to recycle into FREE sectors -----
m_dwFreeSectorsNeeded = dwFreeSectorsNeeded;
m_bCritical = bCritical;
//----- 3. If this is a critical compaction, make sure the "compaction completed" wait event is reset -----
if(bCritical == TRUE)
{
if(!ResetEvent(m_hCompactionComplete))
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::StartCompactor() - Unable to reset the critical Compaction Complete wait event!!!\r\n")));
goto START_ERROR;
}
}
//----- 4. Signal the compactor to start retrieving the requested number of sectors -----
if(!SetEvent(m_hStartCompacting))
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::StartCompactor() - Unable to signal compactor thread!!!\r\n")));
goto START_ERROR;
}
//----- 5. Set the thread priority accordingly -----
if(!CeSetThreadPriority(m_hCompactorThread, dwPriority))
{
ReportError((TEXT("FLASHDRV.DLL:Compactor::StartCompactor() - Unable to set compactor's thread priority!!!\r\n")));
goto START_ERROR;
}
//----- 6. SPECIAL CASE: If this is a CRITICAL compaction request, we must wait for the compaction process -----
// to complete before returning (this compaction is then SYNCHRONOUSLY executed for the caller).
if(bCritical == TRUE)
{
LeaveCriticalSection( &g_csFlashDevice);
if(WaitForSingleObject(m_hCompactionComplete, INFINITE) == WAIT_FAILED)
{
ReportError((TEXT("FLASHDRV.DLL:CompactorThread() - Unable to wait on m_hCompactionComplete event!\r\n")));
EnterCriticalSection( &g_csFlashDevice);
goto START_ERROR;
}
EnterCriticalSection( &g_csFlashDevice);
}
return TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -