📄 chunkres.cpp
字号:
//// ULONG32 offset// char* buf// ULONG32 count// ULONG32* actual//// Return://// HX_RESULT// Possible errors include: TBD.//HX_RESULT CChunkyRes::GetData(ULONG32 offset, char* buf, ULONG32 count, ULONG32* actual){ HX_RESULT theErr = HXR_OK; int ndx; ULONG32 ulFirstChunk = offset/DEF_CHUNKYRES_CHUNK_SIZE; ULONG32 ulLastChunk = (offset+count)/DEF_CHUNKYRES_CHUNK_SIZE; HX_ASSERT(ulFirstChunk < INT_MAX); HX_ASSERT(ulLastChunk < INT_MAX); int nFirstChunk = (int)ulFirstChunk; int nLastChunk = (int)ulLastChunk; HX_ASSERT(m_Chunks.GetSize() >= nLastChunk+1); ULONG32 chunkOffset = offset - (ulFirstChunk*DEF_CHUNKYRES_CHUNK_SIZE); ULONG32 chunkCount = count; ULONG32 baseOffset = 0; *actual = 0; // -fst for (ndx = nFirstChunk; (ndx <= nLastChunk) && chunkCount; ndx++) { CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx]; if (!pChunk) { // with random access, it's feasible that there's a null chunk. theErr = HXR_CHUNK_MISSING; goto exit; } HX_ASSERT_VALID_PTR(pChunk); ULONG32 chunkActual = 0; // Actually get the data from the chunk! ULONG32 chunkAmount = min(DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset,chunkCount); theErr = pChunk->GetData(chunkOffset,buf+baseOffset,chunkAmount,&chunkActual); if (theErr != HXR_OK) { goto exit; } // What?!?! HX_ASSERT(chunkActual == chunkAmount); *actual += chunkActual; // -fst // reduce the chunk count... chunkCount -= chunkAmount; baseOffset += chunkAmount; // only the first chunk has an offset! chunkOffset = 0; } // Remember how many bytes have been served to the user, // in case they want us to discard used data m_ulUsedBytes = offset + *actual; // Discard chunks that have been fully served to the user if (m_bDiscardUsedData) { nLastChunk = (int)(m_ulUsedBytes/DEF_CHUNKYRES_CHUNK_SIZE); for (ndx = m_ulFirstChunkIdx; ndx < nLastChunk - 1; ndx++) { CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx]; HX_ASSERT_VALID_PTR(pChunk); UINT32 ulTempOffset = pChunk->GetTempFileOffset(); pChunk->DiscardDiskData(); // Increment the first valid chunk index m_ulFirstChunkIdx++; if (ulTempOffset) { // Add the disk space to the free space list m_FreeDiskOffsets.AddHead((void*)ulTempOffset); } } }exit: return theErr;}HX_RESULT CChunkyRes::GetContiguousDataPointer(ULONG32 offset, char*& buf, ULONG32 count){ HX_RESULT theErr = HXR_OK; HX_ASSERT(m_bDiscardUsedData == FALSE && m_bDisableDiskIO == FALSE); ULONG32 ulFirstChunk = offset/DEF_CHUNKYRES_CHUNK_SIZE; ULONG32 ulLastChunk = (offset+count)/DEF_CHUNKYRES_CHUNK_SIZE; HX_ASSERT(ulFirstChunk < INT_MAX); HX_ASSERT(ulLastChunk < INT_MAX); // if the required data length spans two chunks, we cannot have // contiguous memory if (ulFirstChunk != ulLastChunk) { return HXR_FAIL; } int nFirstChunk = (int)ulFirstChunk; if (m_Chunks.GetSize() < nFirstChunk+1) { m_Chunks.SetSize(nFirstChunk+1); } CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[nFirstChunk]; if (!pChunk) { pChunk = new CChunkyResChunk(this); if (m_bDisableDiskIO) { pChunk->DisableDiskIO(); } m_Chunks[nFirstChunk] = pChunk; } HX_ASSERT(m_Chunks.GetSize() >= nFirstChunk+1); HX_ASSERT_VALID_PTR(pChunk); ULONG32 chunkOffset = offset - (ulFirstChunk*DEF_CHUNKYRES_CHUNK_SIZE); // Actually get the data from the chunk! ULONG32 chunkAmount = min(DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset, count); theErr = pChunk->GetContiguousDataPointer(chunkOffset,buf,chunkAmount); return theErr;}///////////////////////////////////////////////////////////////////////////////// Method://// CChunkyRes::SetData()//// Purpose://// Sets a block of data in a resource.//// Parameters://// ULONG32 offset// const char* buf// ULONG32 count//// Return://// HX_RESULT// Possible errors include: TBD.//HX_RESULT CChunkyRes::SetData(ULONG32 offset, const char* buf, ULONG32 count){ HX_RESULT theErr = HXR_OK; ULONG32 ulFirstChunk = offset/DEF_CHUNKYRES_CHUNK_SIZE; ULONG32 ulLastChunk = (offset+count)/DEF_CHUNKYRES_CHUNK_SIZE; HX_ASSERT(ulFirstChunk < INT_MAX); HX_ASSERT(ulLastChunk < INT_MAX); int nFirstChunk = (int)ulFirstChunk; int nLastChunk = (int)ulLastChunk; if (m_Chunks.GetSize() < nLastChunk+1) { m_Chunks.SetSize(nLastChunk+1); } ULONG32 chunkOffset = offset - (ulFirstChunk*DEF_CHUNKYRES_CHUNK_SIZE); ULONG32 chunkCount = count; ULONG32 baseOffset = 0; for (int ndx = nFirstChunk; ndx <= nLastChunk; ndx++) { CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx]; if (!pChunk) { pChunk = new CChunkyResChunk(this); if (m_bDisableDiskIO) { pChunk->DisableDiskIO(); } m_Chunks[ndx] = pChunk; } // Actually set the data for the chunk! theErr = pChunk->SetData(chunkOffset,buf+baseOffset,min(DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset,chunkCount)); if (theErr != HXR_OK) { goto exit; } // reduce the chunk count... chunkCount -= (DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset); baseOffset += (DEF_CHUNKYRES_CHUNK_SIZE-chunkOffset); // only the first chunk has an offset! chunkOffset = 0; }exit: return theErr;}void CChunkyRes::TrimDownMemoryMRU(){ // If we have just reduced our allowed memory usage, then // discard the least recently used chunks till we are under // the ne threshold... if (m_CurMemUsage > m_MemUsageThreshold) { while (!m_ChunksMemoryMRU->IsEmpty() && (m_CurMemUsage > m_MemUsageThreshold)) { // Get the least recently used chunk. CChunkyResChunk* pChunk = (CChunkyResChunk*)m_ChunksMemoryMRU->GetTail(); HX_ASSERT_VALID_PTR(pChunk); // Discount its usage. m_CurMemUsage -= pChunk->GetSize(); // Spill this chunk to disk... pChunk->SpillToDisk(); // Remove the chunk from the end of the Memory MRU m_ChunksMemoryMRU->RemoveTail(); // And add the chunk to the front of the Disk MRU m_ChunksDiskMRU->AddHead(pChunk); } // How can this be?!?! Did you really mean to set the memory usage such // that there are no chunks in memory?!? HX_ASSERT(!m_ChunksMemoryMRU->IsEmpty()); }}///////////////////////////////////////////////////////////////////////////////// Method://// CChunkyResChunk::SetMemUsageThreshold()//// Purpose://// Sets the memory usage threshold for the chunky resource chunks.// If if chunk sizes amount to more than the threshold, then the// least recently used ones will be spilled to disk.//// Parameters://// ULONG32 memUsage// Memory usage in bytes which will be allowed for all chunks before// least recently used chunks will be spilled to disk.//// Return://// None.//void CChunkyRes::SetMemUsageThreshold(ULONG32 memUsage){ m_MemUsageThreshold = memUsage; TrimDownMemoryMRU();}///////////////////////////////////////////////////////////////////////////////// Method://// CChunkyRes::CChunkyRes()//// Purpose://// Constructor for a chunky resource.//// Parameters://// None.//// Return://// N/A//CChunkyRes::CChunkyRes() : m_Chunks() , m_strTempFileName() , m_ulNextTempFileChunk(DEF_START_CHUNK_OFFSET) , m_bHasBeenOpened(FALSE) , m_bDisableDiskIO(FALSE) , m_bDiscardUsedData(FALSE) , m_ulFirstChunkIdx(0) , m_ulUsedBytes(0) , m_pMutex(0) , m_MemUsageThreshold(DEF_CHUNKYRES_MEM_THRESHOLD) , m_CurMemUsage(0) , m_ChunksMemoryMRU(NULL) , m_ChunksDiskMRU(NULL) , m_ChunkSize(DEF_CHUNKYRES_CHUNK_SIZE){#if defined(THREADS_SUPPORTED) HXMutex::MakeMutex(m_pMutex);#else HXMutex::MakeStubMutex(m_pMutex);#endif HX_ASSERT(m_pMutex); m_ChunksMemoryMRU = new CHXSimpleList; m_ChunksDiskMRU = new CHXSimpleList; HX_ASSERT(m_ChunksMemoryMRU); HX_ASSERT(m_ChunksDiskMRU);}///////////////////////////////////////////////////////////////////////////////// Method://// CChunkyRes::~CChunkyRes()//// Purpose://// Destructor for a chunky resource.//// Parameters://// None.//// Return://// N/A//CChunkyRes::~CChunkyRes(){ // If we are getting rid of the resource, then // we should discard all of the chunks... for (int ndx = 0; ndx < m_Chunks.GetSize(); ndx++) { CChunkyResChunk* pChunk = (CChunkyResChunk*)m_Chunks[ndx]; if (pChunk) { delete pChunk; } } HX_RESULT theErr = DiscardDiskData(); HX_ASSERT(theErr == HXR_OK); if(m_ChunksMemoryMRU) { HX_ASSERT(m_ChunksMemoryMRU->GetCount() == 0); delete m_ChunksMemoryMRU; m_ChunksMemoryMRU = NULL; } if(m_ChunksDiskMRU) { HX_ASSERT(m_ChunksDiskMRU->GetCount() == 0); delete m_ChunksDiskMRU; m_ChunksDiskMRU = NULL; } HX_DELETE(m_pMutex);}///////////////////////////////////////////////////////////////////////////////// Method://// CChunkyResChunk::MakeSureChunkIsInMemory()//// Purpose://// Get a portion of the data for a chunk.//// Parameters://// ULONG32 offset// char* buf// ULONG32 count// ULONG32* actual//// Return://// HX_RESULT// Possible errors include: TBD.//HX_RESULT CChunkyResChunk::MakeSureChunkIsInMemory(){ HX_RESULT theErr = HXR_OK; // If we don't have a chunk pointer, then we aren't in // memory... if (!m_pChunkData) { // Find ourselves in the MRU list for Disk chunks... LISTPOSITION pos = m_pChunkRes->m_ChunksDiskMRU->Find(this); // If were found in the disk MRU list, then we have // some work to do... if (pos) { // First, remove ourselves from the disk list... m_pChunkRes->m_ChunksDiskMRU->RemoveAt(pos); // Load from disk... theErr = LoadFromDisk(); if (theErr != HXR_OK) { goto exit; } } else { #ifdef _DEBUG { // We shouldn't find ourselves in the MRU list // for memory chunks... but we want to check! LISTPOSITION pos = m_pChunkRes->m_ChunksMemoryMRU->Find(this); // We shouldn't be in this list!!!! HX_ASSERT(pos == NULL); } #endif // end _DEBUG section m_pChunkData = new UCHAR[m_pChunkRes->m_ChunkSize]; if (!m_pChunkData) theErr = HXR_OUTOFMEMORY; if (theErr != HXR_OK) { goto exit; } HX_ASSERT(GetValidLength() == 0); } // Add to the front of the Memory list... m_pChunkRes->m_ChunksMemoryMRU->AddHead(this); m_pChunkRes->m_CurMemUsage += GetSize(); // Make sure we don't have to much info in memory... if (!m_bDisableDiskIO) { m_pChunkRes->TrimDownMemoryMRU(); HX_ASSERT(m_pChunkData); } } // If we are already in memory, then make sure we are at the // top of the Memory MRU list!!! else { // We should find ourselves in the MRU list // for memory chunks... but we want to check! LISTPOSITION pos = m_pChunkRes->m_ChunksMemoryMRU->Find(this); // XXXNH: If we aren't in this list it means we were paged out, // so we only need to put ourselves at the top of the MRU list if (pos) { // First, remove ourselves from wherever we are in the // Memory MRU list... m_pChunkRes->m_ChunksMemoryMRU->RemoveAt(pos); } // And add ourselves to the top of the list! m_pChunkRes->m_ChunksMemoryMRU->AddHead(this); }exit: return theErr;}///////////////////////////////////////////////////////////////////////////////// Method://// CChunkyResChunk::GetValidLength()//// Purpose://// Determines how much of a chunk is valid//// Parameters://// ULONG32 offset//// Return://// HX_RESULT// Possible errors include: TBD.//ULONG32 CChunkyResChunk::GetValidLength(ULONG32 offset /* = 0 */) const{ HX_ASSERT(offset < GetSize()); ULONG32 ulValidLength = 0; LISTPOSITION rangePos = m_ValidRanges.GetHeadPosition(); if (rangePos) { do { ValidRange* pRange = (ValidRange*)m_ValidRanges.GetNext(rangePos); HX_ASSERT(pRange); // see if the offset points into this particular range if (offset >= pRange->offset && offset <= pRange->offset + pRange->length) { ulValidLength = pRange->offset + pRange->length - offset; } } while (rangePos); } return ulValidLength;}///////////////////////////////////////////////////////////////////////////////// Method://// CChunkyResChunk::GetData()//// Purpose://// Get a portion of the data for a chunk.//// Parameters://// ULONG32 offset// char* buf// ULONG32 count// ULONG32* actual//// Return://// HX_RESULT// Possible errors include: TBD.//HX_RESULT CChunkyResChunk::GetData(ULONG32 offset, char* buf, ULONG32 count, ULONG32* actual){ HX_RESULT theErr; if(!count) { *actual = count; return HXR_OK; } // We should have a non-zero valid size if (!GetValidLength(offset)) { // This chunk must have been discarded theErr = HXR_CHUNK_MISSING; goto exit; } // Make sure this chunk is in memory! theErr = MakeSureChunkIsInMemory(); if (theErr != HXR_OK) { goto exit; } // You can't read more than there is room in this chunk. // CChunkyRes should prevent this case... HX_ASSERT(offset+count <= GetSize()); // The call to MakeSureChunkIsInMemory() should have handled this! HX_ASSERT_VALID_PTR(m_pChunkData); *actual = min(count,GetValidLength(offset)); HX_ASSERT(*actual < UINT_MAX); memcpy(buf,m_pChunkData+offset,(int)(*actual)); /* Flawfinder: ignore */exit: return theErr;}HX_RESULT CChunkyResChunk::GetContiguousDataPointer(ULONG32 offset, char*& buf, ULONG32 count){ HX_RESULT theErr = HXR_OK; if(!count) { theErr = HXR_FAIL; goto exit; } // First, make sure this chunk is in memory! theErr = MakeSureChunkIsInMemory(); if (theErr != HXR_OK) { goto exit; } // You can't write more than there is room in this chunk. // CChunkyRes should prevent this case... HX_ASSERT(offset+count <= GetSize()); // Currently, you must write to chunks in order from the // start of the chunk first. Random access may come in the // future... HX_ASSERT(GetValidLength(offset) > 0); // needed still at all? // The call to MakeSureChunkIsInMemory() should have handled this! HX_ASSERT_VALID_PTR(m_pChunkData); AddValidRange(offset, count); HX_ASSERT(count < UINT_MAX); buf = (char*) (m_pChunkData+offset); m_bModified = TRUE;exit: return theErr;}///////////////////////////////////////////////////////////////////////////////// Method://// CChunkyResChunk::AddValidRange()//// Purpose://// Mark a part of this CChunkyResChunk as valid// Called from SetData.//// Parameters://// ULONG32 offset// ULONG32 length// BOOL bValid//// Return://// HX_RESULT// Possible errors include: TBD.//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -