#include <sl.h>
#include <fs.h>
struct CacheEntry {
CICell ih;
long time;
long long offset;
};
typedef struct CacheEntry CacheEntry;
#define kCacheSize (0x80000)
#define kCacheMinBlockSize (0x200)
#define kCacheMaxBlockSize (0x4000)
#define kCacheMaxEntries (kCacheSize / kCacheMinBlockSize)
static CICell gCacheIH;
static long gCacheBlockSize;
static long gCacheNumEntries;
static long gCacheTime;
static CacheEntry gCacheEntries[kCacheMaxEntries];
static char gCacheBuffer[kCacheSize];
unsigned long gCacheHits;
unsigned long gCacheMisses;
unsigned long gCacheEvicts;
void CacheInit(CICell ih, long blockSize)
{
if ((blockSize < kCacheMinBlockSize) ||
(blockSize >= kCacheMaxBlockSize))
return;
gCacheBlockSize = blockSize;
gCacheNumEntries = kCacheSize / gCacheBlockSize;
gCacheTime = 0;
gCacheHits = 0;
gCacheMisses = 0;
gCacheEvicts = 0;
bzero(gCacheEntries, sizeof(gCacheEntries));
gCacheIH = ih;
}
long CacheRead(CICell ih, char *buffer, long long offset,
long length, long cache)
{
long cnt, oldestEntry, oldestTime, loadCache = 0;
CacheEntry *entry;
if (cache && (gCacheIH == ih) && (length == gCacheBlockSize)) {
for (cnt = 0; cnt < gCacheNumEntries; cnt++) {
entry = &gCacheEntries[cnt];
if ((entry->ih == ih) && (entry->offset == offset)) {
entry->time = ++gCacheTime;
break;
}
}
if (cnt != gCacheNumEntries) {
bcopy(gCacheBuffer + cnt * gCacheBlockSize, buffer, gCacheBlockSize);
gCacheHits++;
return gCacheBlockSize;
}
loadCache = 1;
}
Seek(ih, offset);
Read(ih, (CICell)buffer, length);
if (cache) gCacheMisses++;
if (loadCache) {
oldestTime = gCacheTime;
for (cnt = 0; cnt < gCacheNumEntries; cnt++) {
entry = &gCacheEntries[cnt];
if (entry->ih == 0) break;
if (entry->time < oldestTime) {
oldestTime = entry->time;
oldestEntry = cnt;
}
}
if (cnt == gCacheNumEntries) {
cnt = oldestEntry;
gCacheEvicts++;
}
entry = &gCacheEntries[cnt];
entry->ih = ih;
entry->time = ++gCacheTime;
entry->offset = offset;
bcopy(buffer, gCacheBuffer + cnt * gCacheBlockSize, gCacheBlockSize);
}
return length;
}