Files
secondo/Algebras/FileIndexAlgebra/Cache/LruCache.cpp

165 lines
3.5 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
Least recently used cache
*/
#include <fstream> // ifstream
#include <functional> // std::placeholders
#include <iostream> // cout
#include <list> // list
#include <stdexcept> // exception
#include <stdio.h> // fopen
#include <string.h> // memcpy
#include <utility> // pair
#include "LruCache.h"
using namespace std;
using namespace std::placeholders;
namespace fialgebra {
namespace cache {
// Nested class
// CacheElement::CacheElement()
LruCache::CacheElement::CacheElement(
size_t value,
size_t length,
bool changed )
: _value( value ),
_length( length ),
_changed( changed ) { }
// CacheElement::~CacheElement()
LruCache::CacheElement::~CacheElement() { }
// CacheElement::GetValue()
size_t LruCache::CacheElement::GetValue() { return _value; }
// CacheElement::GetLength()
size_t LruCache::CacheElement::GetLength() { return _length; }
// CacheElement::HasChanged()
bool LruCache::CacheElement::HasChanged() { return _changed; }
// ctor
LruCache::LruCache(
const char* fileName,
size_t pageSize,
size_t pageCount )
: CacheBase( fileName, pageSize, pageCount ),
_incCache( pageCount,
std::bind( &LruCache::DeleteCallback, this, _1, _2 ) ) { }
LruCache::~LruCache() {
Flush();
}
// Read
size_t LruCache::Read( size_t pageNo, size_t length ) {
if( _incCache.Contains( pageNo ) ) {
totalHit++;
return ReadCache( pageNo, length );
} // if
totalMiss++;
size_t arr = ReadFile( pageNo, length );
// Das Element wird in den Cache geschrieben,
// hat sich aber ja noch nicht geänder. Deshalb
// ist der letzte Parameter false.
WriteCache( pageNo, arr, length, false );
return arr;
}
// Write
void LruCache::Write( size_t pageNo, size_t arr, size_t length ) {
// Page hat sich potentiell geaender, deshalb ist
// der letzte Parameter true.
WriteCache( pageNo, arr, length, true );
}
// private WriteCache()
void LruCache::WriteCache( size_t pageNo, size_t arr,
size_t length, bool changed ) {
// Wir arbeiten im Cache mit Kopien der Daten, sonst wird
// der Cache inkonsistent, sobald jemand eins der Objekte
// aus dem Speicher löscht.
char* buffer = new char[length];
memcpy( buffer, (char*)arr, length );
_incCache.Put( pageNo,
CacheElement( (size_t)buffer, length, changed ) );
}
// private ReadCache()
size_t LruCache::ReadCache( size_t pageNo, size_t length ) {
CacheElement elem = _incCache.Get( pageNo );
size_t arr = elem.GetValue();
// Auch hier: Wir erstellen eine Kopie der Page.
char* buffer = new char[length];
memcpy( buffer, (char*)arr, length );
return (size_t)buffer;
}
// private DeleteCallback()
void LruCache::DeleteCallback( size_t key, CacheElement elem ) {
// Write back
if( elem.HasChanged() )
WriteFile( key, elem.GetValue(), elem.GetLength() );
// Objekte, die aus dem Cache fliegen, werden auch
// aus dem Speicher gelöscht.
char* arr = (char*)elem.GetValue();
delete[] arr;
}
// Flush
void LruCache::Flush() {
_incCache.Clear();
}
// GetHitRate
double LruCache::GetHitRate() {
size_t total = totalHit + totalMiss;
if( total == 0 ) return 0.0;
return (double)totalHit / total;
}
} // namespace cache
} // namespace fialgebra