📄 cache.cpp
字号:
// cache.cpp
//
#include "stdafx.h"
#include "miniSQL.h"
#include "Cache.h"
extern CMiniSQLApp theApp;
////////////////////////////////////////////////////////////////////
// CBLOCK
CBlock::CBlock()
{
Clear();
}
CBlock::~CBlock()
{
}
void CBlock::Clear()
{
status.dirty = status.lock = false;
status.level = 0;
status.pos = 0;
status.pFile = NULL;
}
Status* CBlock::GetStatus()
{
return &status;
}
char* CBlock::GetBlock()
{
status.level++;
return Block;
}
UINT CBlock::Read(CFile *pFile, long pos)
{
if( !pFile )
throw Error( FILE_OPEN_ERROR, 0, pFile->GetFileName() );
// status.dirty = status.lock = false; //just no change
status.level = 1;
status.pos = pos;
status.pFile = pFile;
long lPos = status.pos << BLOCK_OFFSET;
status.pFile->Seek(lPos, CFile::begin);
return status.pFile->Read(Block, sizeof(Block));
}
bool CBlock::Write()
{
if( status.pFile && status.dirty ){
long lPos = status.pos << BLOCK_OFFSET;
status.pFile->Seek(lPos, CFile::begin);
status.pFile->Write(Block, sizeof(Block));
}
return true;
}
/////////////////////////////////////////////////////////////////////
// CCACHE
int CCache::Next()
{
//Find the next Block which can be used
//using Clockwise algorithm
int i = (last + 1) % CACHE_SIZE;
Status* status = Cache[i].GetStatus();
while( status->level ){
if( !status->lock )
status->level--;
i = (i + 1) % CACHE_SIZE;
status = Cache[i].GetStatus();
}
return i;
}
int CCache::Find(POSITION fPos, long pos)
{
//Find the specified Block
Status *status;
for(int i = CACHE_SIZE - 1; i >= 0; i--){
status = Cache[i].GetStatus();
if( status->pFile == FileList.GetAt(fPos)
&& status->pos == pos )
return i;
}
return -1;
}
POSITION CCache::Find(CFile* pFile)
{
//Find the position in the list corresponding to pFile
POSITION pos = FileList.GetHeadPosition();
while( pos ){
POSITION old = pos;
if( FileList.GetNext(pos) == pFile )
return old;
}
return NULL;
}
POSITION CCache::Open( const char* fname, const char* fsuf )
{
//open a file;
char file_name[ FILE_NAME_LEN + 1 ];
::strncpy( file_name, fname, MAIN_NAME_LEN );
file_name[ MAIN_NAME_LEN ] = 0;
::strncat( file_name, fsuf, FILE_NAME_LEN - MAIN_NAME_LEN );
file_name[ FILE_NAME_LEN ] = 0;
POSITION pos = FileList.GetHeadPosition();
while( pos ){
POSITION old = pos;
if( FileList.GetNext(pos)->GetFileName() == file_name )
return old;
}
//check if the file exists
CFileStatus status;
CFile* pFile;
CString path = theApp.dir;
path = path + "\\" + file_name;
if( !CFile::GetStatus( path, status ) )
{
if( !( pFile = new CFile( path,
CFile::modeCreate | CFile::modeReadWrite) ) )
throw Error( FILE_CREATE_ERROR, 0, path );
}
else
{
if( !( pFile = new CFile( path, CFile::modeReadWrite ) ) )
throw Error( FILE_OPEN_ERROR, 0, path );
}
//add to list
FileList.AddTail(pFile);
return FileList.GetTailPosition();
}
void CCache::Close(POSITION fPos, bool reserve)
{
//check if fPos exist
bool flag = false;
for(int i = 0; i < FileList.GetCount(); i++)
if( FileList.FindIndex( i ) == fPos ){
flag = true;
break ;
}
if( !flag )return ;
//close the cache specified by fPos
CFile* pFile = FileList.GetAt ( fPos );
if( pFile == NULL ) return ;
for(i = 0; i < CACHE_SIZE; i++)
if( Cache[i].status.pFile == pFile ){
if( reserve )Cache[i].Write();
Cache[i].Clear();
}
CString fPath = pFile->GetFilePath();
pFile->Close();
if( !reserve ){
TRY{
CFile::Remove( fPath );
}
CATCH( CFileException, e ){
#ifdef _DEBUG
Message( "File \' " + fPath + " \' can't be removed.\n" );
#endif
}
END_CATCH
}
FileList.RemoveAt( fPos );
pFile = NULL;
}
void CCache::Clear()
{
//clear the cache
for( int i = 0; i < CACHE_SIZE; i++ ){
Cache[i].Write();
Cache[i].Clear();
}
POSITION pos = FileList.GetHeadPosition();
while( pos )
FileList.GetNext( pos )->Close();
FileList.RemoveAll();
last = -1;
}
CBlock* CCache::FetchBlock(POSITION fPos, long pos)
{
//check if fPos exist
bool flag = false;
for(int i = 0; i < FileList.GetCount(); i++)
if( FileList.FindIndex( i ) == fPos ){
flag = true;
break ;
}
if( !flag )return NULL;
//fetch a specified data into memory
if( ( i = Find( fPos, pos ) ) == -1 ){
i = Next();
Cache[i].Write();
Cache[i].Read( FileList.GetAt( fPos ), pos );
}
last = i;
return &Cache[i];
}
void CCache::Read( POSITION fPos, long address, void* vdes, UINT sz)
{
//read data from hareware to memory
char* des = ( char* ) vdes;
UINT m_sz;
CBlock* pBlock;
while( sz > 0 ){
m_sz = BLOCK_SIZE - address % BLOCK_SIZE;
if( m_sz > sz )
m_sz = sz;
pBlock = FetchBlock( fPos, address >> BLOCK_OFFSET );
::memcpy( des, pBlock->GetBlock() + address % BLOCK_SIZE, m_sz );
des += m_sz;
address += m_sz;
sz -= m_sz;
}
}
void CCache::Write( POSITION fPos, long address, const void* vsrc, UINT sz)
{
//write data in memory, change the cache
const char* src = ( const char* ) vsrc;
UINT m_sz;
CBlock* pBlock;
while( sz > 0 ){
m_sz = BLOCK_SIZE - address % BLOCK_SIZE;
if( m_sz > sz )
m_sz = sz;
pBlock = FetchBlock( fPos, address >> BLOCK_OFFSET );
::memcpy( pBlock->GetBlock() + address % BLOCK_SIZE, src, m_sz );
pBlock->status.dirty = true;
src += m_sz;
address += m_sz;
sz -= m_sz;
}
}
/////////////////////////////////////////////////////////////////////
// THE EXTERNAL OBJECT, ONE AND THE ONLY
CCache cache;
/////////////////////////////////////////////////////////////////////
// CFILEAPI
CFileAPI::CFileAPI( const char* fname, const char* fsuf )
{
//construction
//for read
CFileStatus status;
CString path = theApp.dir;
path = path + "\\" + fname + fsuf;
if( !CFile::GetStatus( path, status ) )
throw Error( FILE_OPEN_ERROR, 0, path );
fPos = cache.Open( fname, fsuf );
LoadHead();
}
CFileAPI::CFileAPI( const char* fname, const char* fsuf, long rec_len, long attr_len, bool del_sign )
{
//construction
//open a new file and write
RecCount = AllocList = 0;
RecLen = rec_len;
AttrBlocks = ( attr_len + BLOCK_SIZE - 1 ) / BLOCK_SIZE;
DelSign = del_sign;
fPos = cache.Open( fname, fsuf );
SaveHead();
}
CFileAPI::~CFileAPI()
{
//destruction
if( fPos )
cache.Close( fPos );
}
void CFileAPI::LoadHead()
{
//load all the variables
cache.Read( fPos, 0, &AllocList, ( char* ) &fPos - ( char* ) &AllocList );
}
void CFileAPI::SaveHead()
{
//save the variables
cache.Write( fPos, 0, &AllocList, ( char* ) &fPos - ( char* ) &AllocList );
}
//IMPLEMENTATIONS
long CFileAPI::ntop( long n )
{
//change the number of records to file position or address
return ( DelSign ? ( sizeof( bool ) + RecLen ) * n + sizeof( bool ) : RecLen * n )
+ BLOCK_SIZE * ( AttrBlocks + 1 );
}
void CFileAPI::ReadAttr( void* des, UINT len )
{
cache.Read( fPos, BLOCK_SIZE, des, len );
}
void CFileAPI::WriteAttr( const void* src, UINT len )
{
cache.Write( fPos, BLOCK_SIZE, src, len );
}
void CFileAPI::ReadRec( long n, void* des )
{
cache.Read( fPos, ntop( n ), des, RecLen );
}
void CFileAPI::WriteRec( long n, const void* src )
{
cache.Write( fPos, ntop( n ), src, RecLen );
}
CBlock* CFileAPI::FetchBlock( long bpos )
{
return cache.FetchBlock( fPos, ++bpos + AttrBlocks );
}
long CFileAPI::AllocRec()
{
//allocate a new record
long NewAlloc = AllocList;
if( AllocList == RecCount )
AllocList = ++RecCount ;
else{
cache.Read( fPos, ntop( NewAlloc ), &AllocList, sizeof( long ) );
if( DelSign ){
bool sign = false;
cache.Write( fPos, ntop( NewAlloc ) - sizeof( bool ), &sign, sizeof( bool ) );
}
}
SaveHead();
return NewAlloc;
}
void CFileAPI::RemoveRec( long n )
{
//remove a record
if( DelSign )
{
bool sign = true;
cache.Write( fPos, ntop( n ) - sizeof( bool ), &sign, sizeof( bool ) );
}
cache.Write( fPos, ntop( n ), &AllocList, sizeof( long ) );
AllocList = n;
SaveHead();
}
long CFileAPI::NextRec( long n )
{
//find the next non-empty record
if( n >= RecCount - 1 )
return -1;
if( !DelSign )
return ++n;
bool sign;
do
cache.Read( fPos, ntop( ++n ) - sizeof( bool ), &sign, sizeof( bool ) );
while( sign && n < RecCount - 1 );
return sign ? -1 : n;
}
long CFileAPI::FirstRec()
{
//return the first non-empty record
return NextRec( -1 );
}
void CFileAPI::Close()
{
cache.Close( fPos );
fPos = NULL;
}
void CFileAPI::Drop()
{
//drop the file API for certain reasons
cache.Close( fPos, false );
fPos = NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -