mirror of https://github.com/PCSX2/pcsx2.git
FolderMemoryCard: Optimize file access by keeping a file open between consecutive reads/writes to the same file.
This commit is contained in:
parent
5f8391f9f1
commit
f73db1a572
|
@ -39,6 +39,7 @@ void FolderMemoryCard::InitializeInternalData() {
|
|||
m_timeLastWritten = 0;
|
||||
m_isEnabled = false;
|
||||
m_framesUntilFlush = 0;
|
||||
m_lastAccessedFile.Close();
|
||||
}
|
||||
|
||||
bool FolderMemoryCard::IsFormatted() {
|
||||
|
@ -100,6 +101,8 @@ void FolderMemoryCard::Close() {
|
|||
if ( superBlockFile.IsOpened() ) {
|
||||
superBlockFile.Write( &m_superBlock.raw, sizeof( m_superBlock.raw ) );
|
||||
}
|
||||
|
||||
m_lastAccessedFile.Close();
|
||||
}
|
||||
|
||||
void FolderMemoryCard::LoadMemoryCardData( const bool enableFiltering, const wxString& filter ) {
|
||||
|
@ -589,21 +592,21 @@ bool FolderMemoryCard::ReadFromFile( u8 *dest, u32 adr, u32 dataLength ) {
|
|||
if ( !fileName.DirExists() ) {
|
||||
fileName.Mkdir();
|
||||
}
|
||||
wxFFile file( fileName.GetFullPath(), L"rb" );
|
||||
if ( file.IsOpened() ) {
|
||||
wxFFile* file = m_lastAccessedFile.ReOpen( fileName.GetFullPath(), L"rb" );
|
||||
if ( file->IsOpened() ) {
|
||||
const u32 clusterOffset = ( page % 2 ) * PageSize + offset;
|
||||
const u32 fileOffset = clusterNumber * ClusterSize + clusterOffset;
|
||||
|
||||
file.Seek( fileOffset );
|
||||
size_t bytesRead = file.Read( dest, dataLength );
|
||||
if ( fileOffset != file->Tell() ) {
|
||||
file->Seek( fileOffset );
|
||||
}
|
||||
size_t bytesRead = file->Read( dest, dataLength );
|
||||
|
||||
// if more bytes were requested than actually exist, fill the rest with 0xFF
|
||||
if ( bytesRead < dataLength ) {
|
||||
memset( &dest[bytesRead], 0xFF, dataLength - bytesRead );
|
||||
}
|
||||
|
||||
file.Close();
|
||||
|
||||
return bytesRead > 0;
|
||||
}
|
||||
}
|
||||
|
@ -666,6 +669,8 @@ s32 FolderMemoryCard::Read( u8 *dest, u32 adr, int size ) {
|
|||
memcpy( dest + eccOffset, ecc, eccLength );
|
||||
}
|
||||
|
||||
SetTimeLastReadToNow();
|
||||
|
||||
// return 0 on fail, 1 on success?
|
||||
return 1;
|
||||
}
|
||||
|
@ -712,11 +717,15 @@ s32 FolderMemoryCard::Save( const u8 *src, u32 adr, int size ) {
|
|||
void FolderMemoryCard::NextFrame() {
|
||||
if ( m_framesUntilFlush > 0 && --m_framesUntilFlush == 0 ) {
|
||||
Flush();
|
||||
m_lastAccessedFile.Close();
|
||||
}
|
||||
}
|
||||
|
||||
void FolderMemoryCard::Flush() {
|
||||
Console.WriteLn( L"(FolderMcd) Writing data for slot %u to file system.", m_slot );
|
||||
if ( m_cache.empty() ) { return; }
|
||||
|
||||
Console.WriteLn( L"(FolderMcd) Writing data for slot %u to file system...", m_slot );
|
||||
const u64 timeFlushStart = wxGetLocalTimeMillis().GetValue();
|
||||
|
||||
// first write the superblock if necessary
|
||||
Flush( 0 );
|
||||
|
@ -762,6 +771,10 @@ void FolderMemoryCard::Flush() {
|
|||
Flush( i );
|
||||
}
|
||||
|
||||
m_lastAccessedFile.Close();
|
||||
|
||||
const u64 timeFlushEnd = wxGetLocalTimeMillis().GetValue();
|
||||
Console.WriteLn( L"(FolderMcd) Done! Took %u ms.", timeFlushEnd - timeFlushStart );
|
||||
}
|
||||
|
||||
void FolderMemoryCard::Flush( const u32 page ) {
|
||||
|
@ -873,29 +886,31 @@ bool FolderMemoryCard::WriteToFile( const u8* src, u32 adr, u32 dataLength ) {
|
|||
wxFFile createEmptyFile( fileName.GetFullPath(), L"wb" );
|
||||
createEmptyFile.Close();
|
||||
}
|
||||
wxFFile file( fileName.GetFullPath(), L"r+b" );
|
||||
if ( file.IsOpened() ) {
|
||||
wxFFile* file = m_lastAccessedFile.ReOpen( fileName.GetFullPath(), L"r+b" );
|
||||
if ( file->IsOpened() ) {
|
||||
const u32 clusterOffset = ( page % 2 ) * PageSize + offset;
|
||||
const u32 fileSize = entry->entry.data.length;
|
||||
const u32 fileOffsetStart = std::min( clusterNumber * ClusterSize + clusterOffset, fileSize );;
|
||||
const u32 fileOffsetEnd = std::min( fileOffsetStart + dataLength, fileSize );
|
||||
const u32 bytesToWrite = fileOffsetEnd - fileOffsetStart;
|
||||
|
||||
wxFileOffset actualFileSize = file.Length();
|
||||
wxFileOffset actualFileSize = file->Length();
|
||||
if ( actualFileSize < fileOffsetStart ) {
|
||||
file->Seek( actualFileSize );
|
||||
const u32 diff = fileOffsetStart - actualFileSize;
|
||||
u8 temp = 0xFF;
|
||||
for ( u32 i = 0; i < diff; ++i ) {
|
||||
file.Write( &temp, 1 );
|
||||
file->Write( &temp, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
file.Seek( fileOffsetStart );
|
||||
if ( bytesToWrite > 0 ) {
|
||||
file.Write( src, bytesToWrite );
|
||||
const wxFileOffset fileOffset = file->Tell();
|
||||
if ( fileOffset != fileOffsetStart ) {
|
||||
file->Seek( fileOffsetStart );
|
||||
}
|
||||
if ( bytesToWrite > 0 ) {
|
||||
file->Write( src, bytesToWrite );
|
||||
}
|
||||
|
||||
file.Close();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -980,6 +995,10 @@ void FolderMemoryCard::SetSizeInMB( u32 megaBytes ) {
|
|||
SetSizeInClusters( ( megaBytes * 1024 * 1024 ) / ClusterSize );
|
||||
}
|
||||
|
||||
void FolderMemoryCard::SetTimeLastReadToNow() {
|
||||
m_framesUntilFlush = FramesAfterWriteUntilFlush;
|
||||
}
|
||||
|
||||
void FolderMemoryCard::SetTimeLastWrittenToNow() {
|
||||
m_timeLastWritten = wxGetLocalTimeMillis().GetValue();
|
||||
m_framesUntilFlush = FramesAfterWriteUntilFlush;
|
||||
|
@ -1031,6 +1050,40 @@ void FolderMemoryCard::CalculateECC( u8* ecc, const u8* data ) {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
FileAccessHelper::FileAccessHelper() {
|
||||
m_file = nullptr;
|
||||
}
|
||||
|
||||
FileAccessHelper::~FileAccessHelper() {
|
||||
this->Close();
|
||||
}
|
||||
|
||||
wxFFile* FileAccessHelper::Open( const wxString& filename, const wxString& mode ) {
|
||||
this->Close();
|
||||
m_file = new wxFFile( filename, mode );
|
||||
m_filename = filename;
|
||||
m_mode = mode;
|
||||
return m_file;
|
||||
}
|
||||
|
||||
wxFFile* FileAccessHelper::ReOpen( const wxString& filename, const wxString& mode ) {
|
||||
if ( m_file && mode == m_mode && filename == m_filename ) {
|
||||
return m_file;
|
||||
} else {
|
||||
return this->Open( filename, mode );
|
||||
}
|
||||
}
|
||||
|
||||
void FileAccessHelper::Close() {
|
||||
if ( m_file ) {
|
||||
m_file->Close();
|
||||
delete m_file;
|
||||
m_file = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FolderMemoryCardAggregator::FolderMemoryCardAggregator() {
|
||||
for ( uint i = 0; i < TotalCardSlots; ++i ) {
|
||||
m_cards[i].SetSlot( i );
|
||||
|
|
|
@ -131,6 +131,30 @@ struct MemoryCardPage {
|
|||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// FileAccessHelper
|
||||
// --------------------------------------------------------------------------------------
|
||||
// Small helper class to keep memory card files opened between calls to Read()/Save()
|
||||
class FileAccessHelper {
|
||||
protected:
|
||||
wxFFile* m_file;
|
||||
wxString m_filename;
|
||||
wxString m_mode;
|
||||
|
||||
public:
|
||||
FileAccessHelper();
|
||||
~FileAccessHelper();
|
||||
|
||||
// Get an already opened file if possible, or open a new one and remember it
|
||||
wxFFile* ReOpen( const wxString& filename, const wxString& mode );
|
||||
// Close an open file, if any
|
||||
void Close();
|
||||
|
||||
protected:
|
||||
// Open a new file and remember it for later
|
||||
wxFFile* Open( const wxString& filename, const wxString& mode );
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
// FolderMemoryCard
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
@ -180,6 +204,9 @@ protected:
|
|||
// used to figure out if contents were changed for savestate-related purposes, see GetCRC()
|
||||
u64 m_timeLastWritten;
|
||||
|
||||
// remembers and keeps the last accessed file open for further access
|
||||
FileAccessHelper m_lastAccessedFile;
|
||||
|
||||
// path to the folder that contains the files of this memory card
|
||||
wxFileName m_folderName;
|
||||
|
||||
|
@ -316,6 +343,7 @@ protected:
|
|||
// write data as Save() normally would, but ignore the cache; used for flushing
|
||||
s32 WriteWithoutCache( const u8 *src, u32 adr, int size );
|
||||
|
||||
void SetTimeLastReadToNow();
|
||||
void SetTimeLastWrittenToNow();
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue